DND-5e-LaTeX-Template icon indicating copy to clipboard operation
DND-5e-LaTeX-Template copied to clipboard

DndMonsterAttack spanish

Open tenllado opened this issue 3 years ago • 10 comments

I am using this package to translate an adventure to spanish. Everithing is working flawlessly except the damage type of the \DndMonsterAttack. While in english you would write posion damage, in spanish it would be daño de veneno (damage poison).

I looked at the implementation of the macro, and I think that the piece of code that generates that part is:

    \str_if_empty:NF {\l__dmg_tl} % Don't show any damage if `dmg' is not set.
        {
          \l__dmg_tl\ \l__dmg_type_tl\ \damagename
          \__dnd_if_or_dmg:
          \__dnd_if_plus_dmg:
        }

The thing is that in spanish the first line between the curly braces should be

          \l__dmg_tl\ \damagename\ \l__dmg_type_tl

I do not know how to express this language-dependent change. I am writing this in the hope that it could be an easy change for somebody that knows latex/tex and this library better than me.

Thank you.

tenllado avatar Jun 20 '21 14:06 tenllado

It looks like the official translations use "de daño veneno". Properly fixing requires that line you highlighted to be tokenized. In other words

\renewcommand\damageentryname{|1| \damagename |2|}

Where |1| is \l__damage_tl (the damage passed to the function) and |2| is \l__dmg_type_tl (the damage type: veneno in this case).

In the meantime, you can probably do the following as a workaround. Set \damagename to an empty string in your preamble:

 \renewcommand\damagename{}

Then pass the entire damage description into the attack function (de daño veneno). The spacing might be slightly off, but it may work at the moment. Another option would be to rewrite the attack macro in the preamble, swapping the order of the \damagename and the damage type parameter. You would need to turn the latex3 syntax on and off. This would probably work in the preamble of your document. This is off the top of my head, so no guarantees that it works (and sorry for the messy formatting.

\ExplSyntaxOn % Use tilde (~) for spaces.

\renewcommand\damagename{de~daño}

\cs_renew_protected:Npn \__dnd_if_plus_dmg:  {
    \tl_if_empty:NF {\l__plus_dmg_tl}
    { ~ \plusname\ \l__plus_dmg_tl\ \damagename\ \l__plus_dmg_type_tl }  }

\cs_renew_protected_nopar:Npn \__dnd_if_or_dmg:  {
    \tl_if_empty:NF {\l__or_dmg_tl}    {
      , ~ \orname\ \l__or_dmg_tl\ \damagename\ \l__dmg_type_tl\ \l__or_dmg_when_tl
      \tl_if_empty:NF {\l__plus_dmg_tl}        {,}    }  }

\cs_renew_protected:Npn \__dnd_monster_attack:  {    \__dnd_check_for_key:Nnn \l__name_tl {\DndMonsterAttack} {name}    \__dnd_check_for_key:Nnn \l__mod_tl {\DndMonsterAttack} {mod}
    \begin{DndMonsterAction} {\l__name_tl}~
      \str_case_e:nnF {\l__dnd_attack_distance_tl}        {          { melee }            {              \textit{ \__dnd_caption:nn {\meleeattackname} {\l__dnd_attack_type_tl} : } ~ \__dnd_caption:nn {\tohitname} {\l__mod_tl}, ~ \__dnd_monster_reach:            }          { ranged }            {              \textit{ \__dnd_caption:nn {\rangedattackname} {\l__dnd_attack_type_tl} : } ~ \__dnd_caption:nn {\tohitname} {\l__mod_tl}, ~ \__dnd_monster_range:            }        }        {% Melee and Ranged is the default          \textit{ \__dnd_caption:nn {\meleeorrangedattackname} {\l__dnd_attack_type_tl} : } ~ \__dnd_caption:nn {\tohitname} {\l__mod_tl}, ~ \__dnd_monster_reach:\ \orname\ \__dnd_monster_range:        }      , ~ \l__targets_tl. ~      \textit { \hitname : } ~
      \str_if_empty:NF {\l__dmg_tl} % Don't show any damage if `dmg' is not set.        {          \l__dmg_tl\ \damagename\ \l__dmg_type_tl          \__dnd_if_or_dmg:          \__dnd_if_plus_dmg:        }
      % `extra' is any special text that goes after the final damage; do not      % include the final full stop.      \l__extra_tl .    \end{DndMonsterAction}  }

\ExplSyntaxOff

BrianCriswell avatar Jun 20 '21 14:06 BrianCriswell

Brian, thank you for your help. Apparently this is not working. For some reason that I do not understand changing the definition of \damagename in the preamble is not working and when I try to redefine the protected macros the compiler gives me an error. I will try to further investigate this problem later when I have some time for it. I might have to learn a bit of latex3.

I will let you know if I find some solution and keep an eye on the project in case you manage to solve this internationalization issue.

tenllado avatar Jun 21 '21 10:06 tenllado

The problem in my case is that the pdflatex compiler complains about undefined sequence:

! Undefined control sequence. l.117 \cs_renew_protected:Npn __dnd_monster_attack: ? H The control sequence at the end of the top line of your error message was never \def'ed. If you have misspelled it (e.g., \hobx'), type I' and the correct spelling (e.g., `I\hbox'). Otherwise just continue, and I'll forget about whatever was undefined.

Is like I cannot change a private function of the dnd library. Is it possible to change the private function from outside the library?

tenllado avatar Jun 22 '21 09:06 tenllado

Hello, I could not manage to change the private functions, if anyone can help me with that I would appreciate it.

I found an alternative solution that might not be ideal, but works for me. I created a new cls file dndes.cls to include a new definition of the DocumentCommands: DndMonsterAttack and siblings. This gave me no problems at all. The redefinition of the \damagename did not work either, so I included the modification inside the new private function __dnd_monster_attackes (and siblings). The full content of this file is:

\ProvidesClass{dndes}
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{dndbook}} 
\ProcessOptions\relax
\LoadClass[]{dndbook}
\RequirePackage{expl3}

\ExplSyntaxOn

\cs_new_protected:Npn \__dnd_if_plus_dmges:
  {
    \tl_if_empty:NF {\l__plus_dmg_tl}
    { ~ \plusname\ \l__plus_dmg_tl\ de\ \damagename\ \l__plus_dmg_type_tl}
  }

\cs_new_protected_nopar:Npn \__dnd_if_or_dmges:
  {
    \tl_if_empty:NF {\l__or_dmg_tl}
    {
      , ~ \orname\ \l__or_dmg_tl\ de\ \damagename\ \l__dmg_type_tl\ \l__or_dmg_when_tl

      \tl_if_empty:NF {\l__plus_dmg_tl}
        {,}
    }
  }

\cs_new_protected:Npn \__dnd_monster_attackes:
  {
    \__dnd_check_for_key:Nnn \l__name_tl {\DndMonsterAttack} {name}
    \__dnd_check_for_key:Nnn \l__mod_tl {\DndMonsterAttack} {mod}

    \begin{DndMonsterAction} {\l__name_tl}~

      \str_case_e:nnF {\l__dnd_attack_distance_tl}
        {
          { melee }
            {
              \textit{ \__dnd_caption:nn {\meleeattackname} {\l__dnd_attack_type_tl} : } ~ \__dnd_caption:nn {\tohitname} {\l__mod_tl}, ~ \__dnd_monster_reach:
            }
          { ranged }
            {
              \textit{ \__dnd_caption:nn {\rangedattackname} {\l__dnd_attack_type_tl} : } ~ \__dnd_caption:nn {\tohitname} {\l__mod_tl}, ~ \__dnd_monster_range:
            }
        }
        {% Melee and Ranged is the default
          \textit{ \__dnd_caption:nn {\meleeorrangedattackname} {\l__dnd_attack_type_tl} : } ~ \__dnd_caption:nn {\tohitname} {\l__mod_tl}, ~ \__dnd_monster_reach:\ \orname\ \__dnd_monster_range:
        }
      , ~ \l__targets_tl. ~
      \textit { \hitname : } ~

      \str_if_empty:NF {\l__dmg_tl} % Don't show any damage if `dmg' is not set.
        {
          \l__dmg_tl\ de\ \damagename\ \l__dmg_type_tl
          \__dnd_if_or_dmges:
          \__dnd_if_plus_dmges:
        }

      % `extra' is any special text that goes after the final damage; do not
      % include the final full stop.
      \l__extra_tl .
    \end{DndMonsterAction}
  }

\RenewDocumentCommand {\DndMonsterAttack} {o}
  {
    \group_begin:
      \keys_set:nn { dnd / monster / attack } {#1}
      \__dnd_monster_attackes:
    \group_end:
  }

\RenewDocumentCommand {\DndMonsterMelee} {o}
  {
    \group_begin:
      \keys_set:nn { dnd / monster / attack } { #1, distance = melee }
      \__dnd_monster_attackes:
    \group_end:
  }

\RenewDocumentCommand {\DndMonsterRanged} {o}
  {
    \group_begin:
      \keys_set:nn { dnd / monster / attack } { #1, distance = ranged }
      \__dnd_monster_attackes:
    \group_end:
  }

\ExplSyntaxOff

tenllado avatar Jun 22 '21 10:06 tenllado

That should work for now until we can add a bit more flexibility into the class functions.

The "undefined control sequence" means that I gave you the wrong name for renewing a LaTeX3 function, and I don't have the time to look up the correct one.

As for the localization text, try wrapping the renewcommand line in addtocaptions block. See the lib/langages/espanol.def for an example.

BrianCriswell avatar Jun 23 '21 22:06 BrianCriswell

Hi @tenllado, I also have the same problem with damage types in Portuguese, I'm following this thread and also trying to solve this on my side, I'll let you know if I get any further than you did.

Feel free to reach me if you want :)

vonBarbarosa avatar Sep 07 '21 17:09 vonBarbarosa

I added this to my lib/languages/Portuguese.sty and it seems to work fine (not the best but still), check if it works for you too @tenllado:

\ExplSyntaxOn % Use tilde (~) for spaces.

\addto\captionsportuguese
  {

    ... % The translated commands e.g. \renewcommand\armorclassname{Classe~de~Armadura}, etc

    % Workaround for changing from "<damage_type> \damagename" to "de \damagename <damage_type>"
    \renewcommand\__dnd_if_plus_dmg:
      {
        \tl_if_empty:NF {\l__plus_dmg_tl}
        { ~ \plusname\ \l__plus_dmg_tl\ de\ \damagename\ \l__plus_dmg_type_tl }
      }

    \renewcommand\__dnd_if_or_dmg:
      {
        \tl_if_empty:NF {\l__or_dmg_tl}
        {
          , ~ \orname\ \l__or_dmg_tl\ de\ \damagename\ \l__dmg_type_tl\ \l__or_dmg_when_tl

          \tl_if_empty:NF {\l__plus_dmg_tl}
            {,}
        }
      }

    \renewcommand\__dnd_monster_attack:
      {
        \__dnd_check_for_key:Nnn \l__name_tl {\DndMonsterAttack} {name}
        \__dnd_check_for_key:Nnn \l__mod_tl {\DndMonsterAttack} {mod}

        \begin{DndMonsterAction} {\l__name_tl}~

          \str_case_e:nnF {\l__dnd_attack_distance_tl}
            {
              { melee }
                {
                  \textit{ \__dnd_caption:nn {\meleeattackname} {\l__dnd_attack_type_tl} : } ~ \__dnd_caption:nn {\tohitname} {\l__mod_tl}, ~ \__dnd_monster_reach:
                }
              { ranged }
                {
                  \textit{ \__dnd_caption:nn {\rangedattackname} {\l__dnd_attack_type_tl} : } ~ \__dnd_caption:nn {\tohitname} {\l__mod_tl}, ~ \__dnd_monster_range:
                }
            }
            {% Melee and Ranged is the default
              \textit{ \__dnd_caption:nn {\meleeorrangedattackname} {\l__dnd_attack_type_tl} : } ~ \__dnd_caption:nn {\tohitname} {\l__mod_tl}, ~ \__dnd_monster_reach:\ \orname\ \__dnd_monster_range:
            }
          , ~ \l__targets_tl. ~
          \textit { \hitname : } ~

          \str_if_empty:NF {\l__dmg_tl} % Don't show any damage if `dmg' is not set.
            {
              \l__dmg_tl\ de\ \damagename\ \l__dmg_type_tl
              \__dnd_if_or_dmg:
              \__dnd_if_plus_dmg:
            }

          % `extra' is any special text that goes after the final damage; do not
          % include the final full stop.
          \l__extra_tl .
        \end{DndMonsterAction}
      }
  }

vonBarbarosa avatar Sep 07 '21 19:09 vonBarbarosa

@vonbarbarosa it works for me for french, thanks.

i have just updated this (in \renewcommand__dnd_if_plus_dmg) :

{ ~ \plusname\ \l__plus_dmg_tl\ de\ \damagename\ \l__plus_dmg_type_tl

into this :

{ ~ \plusname\ \l__plus_dmg_tl\ \damagename\ \l__plus_dmg_type_tl }

and this (in \renewcommand__dnd_if_or_dmg:):

, ~ \orname\ \l__or_dmg_tl\ de\ \damagename\ \l__dmg_type_tl\ \l__or_dmg_when_tl

into this

, ~ \orname\ \l__or_dmg_tl\ \damagename\ \l__dmg_type_tl\ \l__or_dmg_when_tl

As in french we have not always "de" before damage type

  • fire damage : dégâts de feu
  • lightning damage : dégâts de foudre
  • acid damage: dégâts d'acide

as you see "de" is not correct for acid type

So i just tweak dmg-type/plus-dmg-type accordingly to have the correct syntax, but its works: dmg-type=de feu, dmg-type=de foudre, dmg-type=d'acide,

And also, i have updated this (in \renewcommand__dnd_monster_attack:):

\l__dmg_tl\ de\ \damagename\ \l__dmg_type_tl

into this:

\l__dmg_tl\ \damagename\ \l__dmg_type_tl

To replace "X de dégâts perforants" by "X dégâts perforants", which is more correct.

Full modified french.sty (renammed in .txt) in attachement.

Thanks !

french.sty.txt

JordyProvost avatar Aug 06 '22 09:08 JordyProvost

Maybe to make this more cleaner, french.sty must call frenchtweaks.sty via \includepackage. But i dont know how to do that without braking everything.

JordyProvost avatar Aug 07 '22 12:08 JordyProvost

Maybe to make this more cleaner, french.sty must call frenchtweaks.sty via \includepackage. But i dont know how to do that without braking everything.

You can just include your customizations in your own .sty file that loads after the class.

This issue is going off-topic. If you want to propose changes to french.sty, please open a new issue, and you can reference this issue for examples.

Long term, the plan is to update the line in question to use a parametrized string similar to how \meleeattackname is handled.

\renewcommand\meleeattackname{Attaque~|1|~au~corps~à~corps}

This will allow each translation to use a different word order.

BrianCriswell avatar Aug 07 '22 14:08 BrianCriswell