How can I access the value of a template variable within a smarty modifier plugin?

108 views Asked by At

I would like to write a Smarty3 modifier that picks a gender dependent word. The gender is defined in the template.

I could use a function like this:

{genderize txt=['maleVersion','femaleVersion','unknownVersion']}

but this looks cumbersome in a textflow. I would prefer something like this:

{'maleVersion|femaleVersion|unknownVersion'|genderize}

I don't know however how to access the $smarty variable from a modifier, like I can from a function.

function smarty_function_gender($parameters = array(), &$smarty)
1

There are 1 answers

1
Rob Ruchte On

As far as I know there is no way to access template vars from within a modifier, but you can just pass the template variable in as a parameter to the modifier.

<?php

function smarty_modifier_genderize($string, $gender)
{
    $genderInputArr = explode('|', $string);
    
    $gender = strtolower($gender);
    
    if(sizeof($genderInputArr) != 3)
    {
        trigger_error('Invalid input', E_USER_WARNING);
    }
    
    switch($gender)
    {
        case 'male':
            return $genderInputArr[0];
        case 'female':
            return $genderInputArr[1];
        default:
            return $genderInputArr[2];
    }
}

Template:

{assign var=gender value='female'}
{'he|she|they'|genderize:$gender}

That's pretty janky though, you're depending on your input always being ordered a certain way.

There are a couple of more robust ways you can approach this. If the only language you need to support is English, the number of gendered words is fairly limited, you probably just need to worry about third person pronouns, and there are only five different variations of each of those, it's a matrix. You can write a simple function to return the correct entry in the table. Since you're already defining the gender in a variable, you only need to pass one parameter into the function to return the desired value. Here's what such a function would look like. You may want to use more terse keys in the table, I was verbose for clarity.

<?php

function smarty_function_pronoun($params, &$smarty)
{
    $gender = $smarty->getTemplateVars('gender');
    $type   = 'subject';
    
    foreach ($params as $_key => $_val)
    {
        switch ($_key)
        {
            case 'type':
                $type = $_val;
                break;
        }
    }
    
    // Be flexible with the gender input
    $genderNormalized = strtolower(substr($gender, 0, 1));
    
    $pronounMap = [
        'm' => [
            'subject'             => 'he',
            'object'              => 'him',
            'possessiveAdjective' => 'his',
            'possessivePronoun'   => 'his',
            'reflexive'           => 'himself'
        ],
        'f' => [
            'subject'             => 'she',
            'object'              => 'her',
            'possessiveAdjective' => 'her',
            'possessivePronoun'   => 'hers',
            'reflexive'           => 'herself'
        ],
        'n' => [
            'subject'             => 'they',
            'object'              => 'them',
            'possessiveAdjective' => 'their',
            'possessivePronoun'   => 'theirs',
            'reflexive'           => 'themself'
        ]
    ];
    
    if (!array_key_exists($genderNormalized, $pronounMap))
    {
        trigger_error('Unsupported gender: ' . $gender, E_USER_NOTICE);
        return;
    }
    
    if (!array_key_exists($type, $pronounMap[$genderNormalized]))
    {
        trigger_error('Unsupported type: ' . $type, E_USER_NOTICE);
        return;
    }
    
    
    return $pronounMap[$genderNormalized][$type];
}

Then in your template you can do this:

{assign var=gender value='male'}
{pronoun type=possessivePronoun}

If you need to support other/multiple languages, or if you want to be more flexible with the content you choose between, you could assign the different content versions to variables and write an even simpler plugin to display the appropriate one.

<?php

function smarty_function_pronoun($params, &$smarty)
{
    $gender = strtolower($smarty->getTemplateVars('gender'));
    
    $male    = $smarty->getTemplateVars('maleVersion');
    $female  = $smarty->getTemplateVars('femaleVersion');
    $unknown = $smarty->getTemplateVars('unknownVersion');
    
    switch ($gender)
    {
        case 'male':
            return $male;
        case 'female':
            return $female;
        default:
            return $unknown;
    }
}

Then in your template:

{assign var=gender value='male'}
{capture assign=maleVersion}Longer content that is relevant to <strong>males</strong> here.{/capture}
{capture assign=femaleVersion}Longer content that is relevant to <strong>females</strong> here.{/capture}
{capture assign=unknownVersion}<em>Neutrally<em> worded content here.{/capture}
{pronoun}