How to translate Form labels?

Permalink
Hi! I'm building a multilingual site in German and English in 5-7.5.13. The Multilingual feature works as expected and is pretty intuitive to use - good job! However, I'm struggling to get a custom view for the Form block translated.

For the form title it works as expected. I wrap it in the tc() function and when I Reload Strings in 'Translate Site Interface', it is picked up and I can translate it.
<h2><?php echo tc('Form', 'Room Inquiry');?></h2>


However, with the form labels inside the foreach loop, only one of the strings is picked up.

<?php  foreach ($questions as $question):
                    <div class="form-group field field-<?php echo $question['type']; ?>
 <?php echo isset($errorDetails[$question['msqID']]) ? 'has-error' : ''?>">
                        <label <?php echo $question['labelFor']; ?>>
                            <?php echo t($question['question']);?>
                            <?php if ($question['required']):?><span class="text-muted small" style="font-weight: normal"><?php echo "*"?></span> 
                        <?php  endif; ?></label>
                        <?php echo $question['input']; ?>
                    </div>
                </div>
                <?php endforeach; ?>


In the form I have field named 'Phone'. Only this string is picked up when I reload the strings.

<?php echo t($question['question']);?>


I suspect it is only picked up and translated because this string also appears in other places around the site. See below entry in my de_CH.po file.

#: application/blocks/msv_location_map/templates/msv_location_map/view.php:108
#: application/single_pages/dashboard/map_locations/locations/view.php:170
#: packages/views/blocks/msv_location_map/view.php:106
#: packages/views/single_pages/dashboard/map_locations/locations/view.php:170
msgid "Phone"
msgstr "Telefon"


The other strings in the form labels such as "First Name", "Adults" and "Children" are not picked up when I reload the strings. I think I might have to add these to the file manually, because the t() function does not work in a loop...

Any pointers?

 
jero replied on at Permalink Reply
jero
It's certainly true that if your translation files don't have the required translations, then the labels won't be translated. You would need to add them but also compile the .po file into a .mo file which is what the t() function will use.

You can do this compilation using msgfmt on the command line. msgfmt is part of the gettext package.
Gondwana replied on at Permalink Reply
Gondwana
I don't know what I'm talking about.

But I'm wondering whether t() expects a literal. Could you refactor things such that t() is used when you add each of the literal values to $question[]?
jero replied on at Permalink Reply
jero
The t() function doesn't care if it gets a literal or a string variable. It works fine in a loop:

$foo = array('Edit','Dashboard','Sign Out');
foreach ($foo as $word) {
   echo t($word).PHP_EOL;
}


outputs

Bearbeiten Verwaltung Abmelden

when I switch the language to de_DE
JohntheFish replied on at Permalink Reply
JohntheFish
Putting a variable inside t($variable) works technically, but is discouraged from use as far as practical because translation string extractors won't find the original strings. So anyone translating would need to dig through the code to find the origin of a variable rather than simply have the string presented to them by the t-string extractor.
Gondwana replied on at Permalink Reply
Gondwana
Based on
https://documentation.concrete5.org/developers/concepts/localization...
t() wants a constant, although you can use t('%s', <const expression>). I can't see how that would help you within a loop, though. I'd still try wrapping the individual strings in t() when you initialise $questions. That way, each string gets a t() and you don't have to worry about t() in your loop.
mlocati replied on at Permalink Best Answer Reply
mlocati
The string that will be extracted by the translation system is the first argument of the t() function.
So, when using
t('%s', $something);

the translation system will allow you to translate %s.
What's the translation of %s? It will always be %s... So this approach doesn't make sense.

The first argument of the t() function must me the literal string to be translated.
Since in this case we don't know the literal strings to be translated a priori, we have the following solutions:

1. we write a PHP file that won't be executed, but that contains the literal strings to be translated. This has been done for instance in the core in this file:
https://github.com/concrete5/concrete5/blob/develop/concrete/src/Sup...

2. since concrete5 8.1, if we are developing a package, we can add a getTranslatableStrings method that accepts a \Gettext\Translations instance: in this method you can add the strings to be translated (you'll be able to translate these strings in the /dashboard/system/multilingual/translate_interface dashboard page).
In this case, this getTranslatableStrings method should read the question texts, and add them to the \Gettext\Translations instance.
Gondwana replied on at Permalink Reply
Gondwana
@mlocati: are you sure that
t('%s', $something)
won't work?

The documentation at
https://documentation.concrete5.org/developers/concepts/localization...
recommends something like
t('Edit %s', $blockTypeName)
I just simplified it further to suit the context of this thread. If this is wrong, then we need to get the documentation changed.
mlocati replied on at Permalink Reply
mlocati
Absolutely sure (I wrote that doc).
Translating "Edit %s" is meaningful (for instance, I'd translate it into Italian as "Modifica %s").
I would translate "%s" as "%s"...
Again, please remark that the translation system can only work on literal strings used as the first parameter of t().
Gondwana replied on at Permalink Reply
Gondwana
@mlocati: thanks. I understand now.
publicb replied on at Permalink Reply
Grazie, I think I will use that approach to solve my problem!