Using Drupal, how do I force t('') to populate the string? - php

I am trying to make sure that all of the translatable strings are present in the database. Some of them appear very rarely (various form validation errors), therefore it would be a pain to reproduce them all.
Instead, I've created an admin module that, once called, goes through an array of all translatable strings and executes echo t('[the string from the array]').
After this, I expect to be able to translate those strings using admin/config/regional/translate/translate. But not all of them are there.
What am I missing?
If that's for some reason not possible, is there any function that would force entry?

Install and use "Translation template extractor" module as suggested by Vlad Stratulat.
The module let you parse all of your modules and themes and extract all the strings that are used in t() function.
The result is a .po file with all the original/translation string pairs.
You can open the .po (it's a plain text file, so use your favorite text-editor or POEdit software) and check and translate the missing strings.
Finally re-upload the complete .po in Drupal.

Try the following.
foreach(array(t('foo'), t('bar')) as $t) {
echo $t;
}
You should never use t() to translate variables, such as calling t($text). Read about t() function.
But anyway, the best way is to create .po file from your module and export it to Drupal using Translation template extractor.
This module will extract all your translatable strings and will save it into language specific file which you can then use in any other sites where you would like to use your module.

Related

Is using echo rather than printf a trouble maker for string translation using .pot file and Poedit?

I was wondering could the use of echo in php code rather than the use of printf() be the cause of a .mo file or in general the reason why the translation files do not work at all?
For Example:
In my php code I have this line of code:
echo __('Twinkle Twinkle little star');
Which has the double underscore identifier __().
When using Poedit, I get my string displayed in the translatable strings column, so that's not an issue.
Sum up:
Could echo cause a problem with the translation even thought Poedit can index and understand that the string is there?
Thanks in advance for your time.
echo and printf are not related to translations. They are merely ways to output a string.
The translating is performed by the __() function. So assuming you have your locale set to French with the proper files loaded:
echo "Hello";
// Hello
echo __("Hello");
// Bonjour
printf("Hello");
// Hello
printf(__("Hello"));
// Bonjour

How do I configure emacs for proper PHP development?

My current setup in emacs for PHP development has a variety of shortcomings. I often use a mixed mode of html and php. I want the mode to be able to recognize what context I'm in and format appropriately. I am especially interested in appropriate tabbing. This is the most important feature for me. Correct coloring would be nice, but if it messes up once in a while that's ok.
I am currently using multi-web-mode and the default php-mode in Emacs 24.3 on MacOS X.
One of the most frustrating problems is incorporating the heredoc syntax: echo <<< My current system doesn't recognize that this syntax needs to be NOT tabbed. I typically get warnings like this:
Indentation fails badly with mixed HTML/PHP in the HTML part in
plaĆ­n `php-mode'. To get indentation to work you must use an
Emacs library that supports 'multiple major modes' in a buffer.
Parts of the buffer will then be in `php-mode' and parts in for
example `html-mode'. Known such libraries are:
mumamo, mmm-mode, multi-mode
You have these available in your `load-path':
mumamo
I've already tried using mumao/nxhtml but that didn't give me the results I wanted. In some ways it was worse. I'd really appreciate any tips people have for getting a working php development environment setup for emacs.
I use web-mode (http://web-mode.org/) for mixed HTML/PHP files and php-mode for pure PHP files. The latest version of php-mode also recommended web-mode for mixed HTML/PHP files: https://github.com/ejmr/php-mode#avoid-html-template-compatibility.
Unlike other modes like mmm-mode, mumamo or multi-web-mode that try to apply different behaviors to different parts of a buffer, web-mode is aware of all the available syntax/template that can be mixed with HTML. You can also use web-mode for mixed HTML files/templates such as Twig, Django, ERB... In fact I use web-mode for anything involve HTML.
There is a catch for PHP template though: Other template systems has different file extension so it is easy to switch the mode automatically, but PHP templates usually use the same .php extension; so I have to make it switch by folders or sometimes manually invoke M-x web-mode. Here's my current configuration:
(defun add-auto-mode (mode &rest patterns)
(mapc (lambda (pattern)
(add-to-list 'auto-mode-alist (cons pattern mode)))
patterns))
(add-auto-mode 'web-mode
"*html*" "*twig*" "*tmpl*" "\\.erb" "\\.rhtml$" "\\.ejs$" "\\.hbs$"
"\\.ctp$" "\\.tpl$" "/\\(views\\|html\\|templates\\)/.*\\.php$")
BTW, try to separate your PHP files and templates and keep the mixed HTML/PHP file as simple as possible (refactor long PHP blocks into functions in a pure file). The code will be easier to read/follow.

xgettext won't scan plural form

I use Poedit for my gettext i18n and that works fine. I use ZF2 where there are view helpers to integrate the translations. One is translate, the other translatePlural.
Usage:
<?php echo $this->translate('Welcome') ?>
<?php echo $this->translatePlural('Item', 'Items', $number) ?>
In Poedit I add the keywords translate and translatePlural. The normal translations work fine, but for the plural forms, only the "Item" is found (and not the "Items"). Just for testing purposes, I replaced the $this->translatePlural() call with ngettext(), but I end up with the same result. My conclusion: (my version of) Poedit is unable to scan plural forms.
What should I enter as keyword to let Poedit scan the second string as well?
After some further search, I stumbled upon the syntax [function]:1,2. That did the trick for me. I have now identified these two functions as keywords for Poedit as follows:
translate
translatePlural:1,2
And now my second argument is scanned.

Permanently write variables to a php file with php

I need to be able to permanently change variables in a php file using php.
I am creating a multilanguage site using codeigniter and using the language helper which stores the text in php files in variables in this format:
$lang['title'] = "Stuff";
I've been able to access the plain text of the files using fopen() etc and I it seems that I could probably locate the areas I want to edit with with regular expressions and rewrite the file once I've made the changes but it seems a bit hacky.
Is there any easy way to edit these variables permanently using php?
Cheers
If it's just an array you're dealing with, you may want to consider var_export. It will print out or return the expression in a format that's valid PHP code.
So if you had language_foo.php which contained a bunch of $lang['title'] = "Stuff"; lines, you could do something along the lines of:
include('language_foo.php');
$lang['title2'] = 'stuff2';
$data = '$lang = ' . var_export($lang, true) . ';';
file_put_contents('language_foo.php', '<?PHP ' . $data . ' ?>');
Alternatively, if you won't want to hand-edit them in the future, you should consider storing the data in a different way (such as in a database, or serialize()'d, etc etc).
It looks way easier to store data somewhere else (for instance, a database) and write a simple script to generate the *.php files, with this comment on top:
#
# THIS FILE IS AUTOGENERATED - DO NOT EDIT
#
I once faced a similar issue. I fixed it by simply adding a smarty template. The way I did it was as follows:
Read the array from the file
Add to the array
Pass the array to smarty
Loop over the array in smarty and generate the file using a template (this way you have total control, which might be missing in reg-ex)
Replace the file
Let me know if this helps.
Assuming that
You need the dictionary file in a human-readable and human-editable form (no serializing etc.)
The Dictionary array is an one-dimensional, associative array:
I would
Include() the dictionary file inside a function
Do all necessary operations on the $lang array (add words, remove words, change words)
Write the $lang array back into the file using a simple loop:
foreach ($lang as $key => $value)
fwrite ($file, "\$lang['$key'] = '$value';\n";
this is an extremely limited approach, of course. I would be really interested to see whether there is a genuine "PHP source code parser, changer and writer" around. This should be possible to do using the tokenizer functions.
If it also is about a truly multilingual site, you might enjoy looking into the gettext extension of PHP. It falls back to a library that has been in use for localizing stuff for many years, and where tools to keep up with the translation files have been around for almost quite as long. This makes supporting all the languages in later revisions of the product more fun, too.
In other news, I would not use an array but rather appropriate definitions, so that you have a file
switch ($lang) {
case 'de':
define('HELLO','Hallo.');
define('BYE','Auf wiedersehen.');
break;
case 'fr':
define('HELLO','Bonjour');
define('BYE','Au revoir.');
break;
case 'en':
default:
define ('HELLO','Hello.');
define ('BYE','Bye.');
}
And I'd also auto-generate that from a database, if maintenance becomes a hassle.
Pear Config will let you read and write PHP files containing settings using its 'PHPArray' container. I have found that the generated PHP is more readable than that from var_export()

How does gettext handle dynamic content?

In php (or maybe gettext in general), what does gettext do when it sees a variable to dynamic content?
I have 2 cases in mind.
1) Let's say I have <?=$user1?> poked John <?=$user2?>. Maybe in some language the order of the words is different. How does gettext handle that? (no, I'm not building facebook, that was just an example)
2) Let's say I store some categories in a database. They rarely, but they are store in a database. What would happen if I do <?php echo gettext($data['name']); ?> ? I would like the translators to translate those category names too, but does it have to be done in the database itself?
Thanks
Your best option is to use sprintf() function. Then you would use printf notation to handle dynamic content in your strings. Here is a function I found on here a while ago to handle this easily for you:
function translate()
{
$args = func_get_args();
$num = func_num_args();
$args[0] = gettext($args[0]);
if($num <= 1)
return $args[0];
return call_user_func_array('sprintf', $args);
}
Now for example 1, you would want to change the string to:
%s poked %s
Which you would input into the translate() function like this:
<?php echo translate('%s poked %s', $user1, $user2); ?>
You would parse out all translate() functions with poEdit. and then translate the string "%s poked %s" into whatever language you wanted, without modifying the %s string placeholders. Those would get replace upon output by the translate() function with user1 and user2 respectively. You can read more on sprintf() in the PHP Manual for more advanced usages.
For issue #2. You would need to create a static file which poEdit could parse containing the category names. For example misctranslations.php:
<?php
_('Cars');
_('Trains');
_('Airplanes');
Then have poEdit parse misctranslations.php. You would then be able to output the category name translation using <?php echo gettext($data['name']); ?>
To build a little on what Mark said... the only problem with the above solution is that the static list must be always maintained by hand and if you add a new string before all the others or you completely change an existing one, the soft you use for translating might confuse the new strings and you could lose some translations.
I'm actually writing an article about this (too little time to finish it anytime soon!) but my proposed answer goes something like this:
Gettext allows you to store the line number that the string appears in the code inside the .po file. If you change the string entirely, the .po editor will know that the string is not new but it is an old one (thanks to the line number).
My solution to this is to write a script that reads the database and creates a static file with all the gettext strings. The big difference to Mark's solution is to have the primary key (let's call it ID) on the database match the line number in the new file. In that case, if you completely change one original translation, the lines are still the same and your translator soft will recognize the strings.
Of course there might be newer and more intelligent .po editors out there but at least if yours is giving you trouble with newer strings then this will solve them.
My 2 cents.
If you have somewhere in your code:
<?=sprintf(_('%s poked %s'), $user1, $user2)?>
and one of your languages needs to swap the arguments it is very simple. Simply translate your code like this:
msgid "%s poked %s"
msgstr "%2$s translation_of_poked %1$s"

Categories