In Magento, performing a translation in modules involves invoking a helper and calling its translation function, E.G.
Mage::helper("core")->__("This is a string to translate");
However, I haven't found any resources online regarding translating strings that contain variables. From past experience, I know that this is usually handled by using a token inside the string, with token replacements defined using additional arguments.
For example, GNU gettext's manual recommends using format strings for translation:
sprintf (gettext ("Hello %s!"), username ());
While Yii Framework has a similar, but subtly different format:
Yii::t("default", "Hello {username}!", array("username"=>username()));
From a quick grep of Magento's core files, it looks like Magento uses C-style format strings, for example in Mage_Adminhtml_Block_Api_User_Edit::getHeaderText the following can be found:
return Mage::helper('adminhtml')->__("Edit User '%s'", $this->escapeHtml(Mage::registry('api_user')->getUsername()));
But I would like further confirmation or advice since online documentation is quite sparse.
Magento uses following syntax for translation:
Mage::helper('catalog')->__("This is %s text %s", "First String", "Second String");
As suggested by Markus Harrison, I am adding these documentation for format strings:
Formatting link 1
Formatting link 2 - wiki
Related
I'm writing a wordpress plugin and planning it's drupal implementation i'm wrapping wordpress functions into adapters. So i wrote an adapter for the __() which is simply
class Ai1ec_Wordpress_Template_Adapter implements Ai1ec_Template_Adapter {
...
public function translate( $text ) {
return __( $text, AI1EC_PLUGIN_NAME );
}
I'm not a big expert of gettext and a collegue wrote me:
will fail when the code is parsed by xgettext to generate the .pot
file. WP i18n functions such as __() require that a string literal is
passed as the first argument, never a variable. And IIRC, the same
holds true for Drupal's t() function.
I've read the codex entries
http://codex.wordpress.org/I18n_for_WordPress_Developers#Placeholders
http://api.drupal.org/api/drupal/includes%21bootstrap.inc/function/t/7
And couldn't find out something exactly related to this. Can soemone explain me exactly why this wouldn't work and how could i write something which could be compatible with Wordpress and Drupal?
In general your colleague is correct, if you pass variables to translation functions they will not get translated unless the same string is passed in as a literal elsewhere. This is because generating the translation template does not run the code, it searches over it for particular function names. The translation methods have 2 purposes, one is to translate the parameter, the second is to identify to the translation template generation program which strings should be included in the translation template file.
You need to tell the translation template generation code (usually the xgettext) program that the parameters to your function are translatable strings. With xgettext this can be done with the -k parameter. WordPress may already have its own wrapper to xgettext that you can use.
The drupal document you linked explicitly says you should not pass variables to t() unless you are sure that the text is passed as a literal elsewhere.
Both the Wordpress and Drupal versions should take strings held in variables.
The Drupal version is somewhat confusingly worded. What the Drupal docs are saying is that you should be careful if the source of the original text is user generated.
$foo = 'bar';
($foo == 'bar') == true;
This may seem like a really daft question, but what is the reason for the existence of the printf() function in PHP?
It seems to me that that using echo will achieve the exact same results, with the added bonus that you don't get confused if you have several variables being output on one line (true, you can use %1$s as opposed to just %s, but it can still get messey with a few variables all being declared).
I know you can also define the type of the variable, without the need to amend it before outputting the string, but to me that doesn't seem like enough to warrent creating a function.
Maybe I'm wrong, maybe I'm missing something obvious, but if someone can help me to understand why it exists (so that I know whether or not I should really be using it!) I'd appriciate it. Thanks.
echo is language construct, printf is a function. It means that so you won't be able to use echo in the same way as printf.
IT'S NOT JUST PERSONAL TASTE
Take a look to the manual pages for both functions:
echo: http://php.net/manual/en/function.echo.php
printf: http://php.net/manual/en/function.printf.php
This topic is discussed there, for example, you cannot call echo with variable functions. Moreover the way they get and manage the input is different. If you do not need the parameters FORMATTING provided by printf you should use echo (it's slightly faster).
Examples
I insist again on some keywords: formatting and function.
The use of printf isn't to concatenate strings or to build a string from placeholders but to do it with custom formatting (possibly from configuration, user inputs or whatever else).
I write some code to explain what I mean (original source in the links I posted).
This code is not valid, echo is not a function so it won't return the printed value (you may use print or sprintf for this but print does not provide string concatenation).
($some_var) ? echo 'true' : echo 'false';
Following code prints a formatted string, in this case the format comes from a literal variable but it may comes from (for example) a GET request or whatever else. Can you rewrite it with echo and the formatting string taken from the configuration?
%format = "%'.-15.15s%'.6.6s\n";
printf($format, $heading1, $value1);
printf() is a port of C's printf() function, so people who got a background writing C code are more familiar with the syntax and will prefer it.
However, most people who start with PHP find it rather confusing.
For comparison:
$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
mysql_real_escape_string($user),
mysql_real_escape_string($password));
(I used sprintf(), which is the same as printf but it won't actually print the string, it just returns it)
$query = "SELECT * FROM users WHERE user='" . mysql_real_escape_string($user) . "' AND password='" . mysql_real_escape_string($password) . "'";
It's just a matter of preference!
This is about separating static string and formatting, and data.
This separation is encouraged in every programming language that I know of because:
intent of programmer is clearer and enforced
intent is clear: When you read this you know what type is awaited for each field:
printf("a: %.2f, b: %s, c: %d", $a, $b, $c)
intent is enforced: silly type errors are limited (as for the security concerns).
it's more secure
Because it limits silly injection of unexpected meta-strings:
$avg = 3.1415;
// $avg = '3</td>pawned!';
printf("average: %.2f", $avg);
It's much worse in SQL...
usually much easier to read
Appart than you have more clues to the intent of the writer, the string
is clearly in one unique clear block. Data are cleanly listed one by one
after. You don't overuse things like ", . all over the place.
it's very powerfull
I'm curious to see how you would do the following without printf:
printf("%.2f %5d", $v1, $v2);
it's some sort of standard of programming
A lot of other programming languages (C, C++, Java, Python, Bash...) will have
similar printf format and way to treat strings.
So its good for you to know it, and for those who already know, it's easier.
And as a consequence there are plenty of docs and tutorials everywhere on the
subject, and a wikipedia page for it: print format string
The strings can be separated from your data automatically
And this means it's available for translation or syntax correction.
You'll find similar concerns with:
prepared statements in mysql that are now enforced with mysql_query being
deprecated in php 5.5 in favor for prepared statements.
All templating language: where you have the template usually in a different langage,
and the data the other side to render the template.
The more general topic is covered on wikipedia: string interpolation
A last precision:
echo does nothing more than outputing a string. And printf does string interpolation, and outputs a string.
So to be fair, we are here comparing building string via string concatenation vs string interpolation. As there's nothing wrong to output a string with echo. So this is not about echo but how you make your string. You are doing string interpolation even when using echo like this:
echo sprintf("avg: %.3f", $avg);
But then, well there are no more difference between this last form and:
printf("avg: %.3f", $avg);
printf probably exists because PHP was created in C, and printf is traditionally used to output formatted strings in C. printf can actually do a lot more than echo because it can output variables in a variety of formats including decimals to certain places and probably a lot more.
That being said, you can do anything that printf can do with some combination of PHP functions, and it may make more sense depending upon your background.
I'll just explain what I did so you get a clear difference, I'm not a PHP Pro, so maybe I'm wrong and there is a better or easier approach, and also my example may be not so useful to you as well.
I pass each string I want to translate to a function, and it returns the translated string, based on source string and current language, this way it would translate:
"The cat has %d kittens." (english) <=> "Katua %d kume ditu." (euskera)
The fact is that the splitted string for the echo couldn't be translated, as the part previous to the number is not the same for every language, so it must be translated as a "single entity".
It's legacy from C inherited by the PHP language
function http://www.cplusplus.com/reference/clibrary/cstdio/sprintf/
printf takes input differently: you can provide a format string and then list all the required input (just like in C/C++).
'echo' and 'print' only take strings and are easier to use.
Your wish, Your style :)
NOT THAT:
as Others have said echo is a language construct and printf is a real function,
You can do lot with printf.
People coming from C/C++ background know a lot of format strings like %f, %d, %.2f and what not !!!!!
They would prefer printf to echo for this scenario as these floating point precison format and others will be at their finger-tips.
They wd prefer these over PHP's inbuilt format functions.
I am building a multilingual application in PHP + CodeIgniter. I have settled upon using gettext for UI text translation, and so far it has proven efficient and easy to work with.
But now I am facing something really annoying: the gettext() function only accepts one parametre, while I'd like a printf-like behaviour that I get from Zend Framework's gettext adapter, where I can use %1$s, %2$s etc. as placeholders and then specify the replacement strings as additional parametres to Zend view's translate() function.
I do not wish to ditch gettext due to the easy translation management with .po files and poEdit (I can get it updated with a single click, after all). What are my options?
I have already tried writing a helper to interact with gettext: run the first argument through gettext and then run strtr on the resulting string. Are there any other/better approaches you would recommend?
It's quite simple actually, you define a variadic function like this:
function myGettext($id)
{
return vsprintf(gettext($id), array_slice(func_get_args(), 1));
}
Now doing myGettext('%u %s in a %s', 3, 'monkeys', 'tree') will return the expected string with the placeholders replaced by the remaining arguments. You obviously also need to implement a plural aware function that calls ngettext() instead.
Regarding poEdit, you have to modify the keywords it searches for, it's been a while since I last used it but it was quite simple, the only problem I faced was identifying keywords for plural support (see this).
Hope it helps!
Reading about Kohana templates and saw something I've never seen before:
$this->template->title = __('Welcome To Acme Widgets');
What does __('Text') mean? What is it? What does it do?
In Kohana (version 3) the function is defined in system/base.php and is a convenience function to aid (as the other answers have mentioned) internationalization. You provide a string (with, optionally, some placeholders to substitute values into the finished text) which is then interpreted and, if required, a translation is returned.
Contrary to assumptions in other answers, this does not use gettext.
A very basic example would be (this particular string is already translated into English, Spanish and French in Kohana):
// 1. In your bootstrap.php somewhere below the Kohana::init line
I18n::lang('fr');
// 2. In a view
echo __("Hello, world!"); // Bonjour, monde!
The double '__' is used for Localization in CakePHP (and possible other frameworks)
http://book.cakephp.org/view/163/Localization-in-CakePHP
It means someone created a function named __ (That's two underscores next to one another.)
My guess is it defined somewhere in the Kohana documentation.
It's string gettext ( string $message ): http://php.net/manual/en/function.gettext.php
Returns a translated string if one is
found in the translation table, or the
submitted message if not found.
The __() is just an alias for it. So __("some text") is equivalent to gettext("some text")
edit: Actually if it's two underscores than it isn't gettext(). The alias for gettext() is one underscore.
Second edit: It looks like __() might be another alias for gettext(). With a slightly different meaning from _(). See here: http://groups.google.com/group/cake-php/browse_thread/thread/9f501e31a4d4130d?pli=1
Third and final edit: Here's an article explaining it in more detail. Looks like it isn't a built in function, but rather something that is commonly added in a lot of frameworks. It is essentially an alias of gettext - it performs the same function. However, it isn't a direct alias (I don't think). It is implemented in and is specific to the framework. It searches for and returns a localization or translation of the string it is given. For more, see this blog post: http://www.eatmybusiness.com/food/2007/04/13/what-on-earth-does-a-double-underscore-then-parenthesis-mean-in-php-__/7/
// Display a translated message
echo __('Hello, world');
// With parameter replacement
echo __('Hello, :user', array(':user' => $username));
See http://kohanaframework.org/3.2/guide/api/I18n for details.
I'm writing Content Management software in PHP (which should not be bigger then 3kb when minified), but what engine should I use for languages (english, dutch, german, chinese, etc...)? I was thinking of creating a function called
function _(){}
that reads strings from a file (a .ini file or similar). But does somebody has an (preferably one with as less code as possible) engine that might be smaller or faster?
I'm not sure if these engines exist already, if not, please say and I will use the _() function.
If I were you I would make my translation function like such (which I believe is very similar to gettext): make it into an sprintf()-like function and translate based on the format string, like so:
function __() {
$a = func_get_args();
$a[0] = lookup_translation($a[0]);
return call_user_func_array("sprintf", $a);
}
Now, you can use the function simply like this:
echo __("Thanks for logging in, %s!", $username);
And in a data file somewhere you have:
"Thanks for logging in, %s!"="Merci pour enlogger, %s!" (*)
The advantages of this are:
You don't have to think up identifiers for every single message: __("login_message", $username), __("logout_message", $username), etc...
You don't immediately have to write a translation for the string, which you would have to if you just used an identifier. You can defer the translation until later, once you're done coding and everything works in English.
(Similarly) You don't have to translate all strings for all languages at once, but you can do it in chunks
For maximum convenience, I would make the __ function log untranslated messages somewhere, so you don't have to go hunting for untranslated strings. Let the system tell you what needs to be translated!
(*) Disclaimer: I don't speak French ;)
You can't use _() because this is a build-in function for internationalization. You are free to roll your own function (call it __()) or use the build-in one which uses the widespread gettext system.
Drupal, for example, uses function t() for this purposes.