Jump to content
Webrocker

Using translatable strings across template files

Recommended Posts

Hi,

I'm toying with the idea of having a central place in PW's translation system for phrases and strings that are frequently used throughout several template files.

The way I understand PWs translation system after reading the docs (http://processwire.com/api/multi-language-support/code-i18n/) is that everytime a __('translate-me') is used in a different .php file, the system will pull that 'translate-me' in a context of the .php file where it is used - so basically all translatable strings of _one_ file at a time are manageable via the (very cool) translation tool in PW's admin interface.

So if for example I were to use __('Daytime phone number') in, lets say, the home.php as well as in the login.php and maybe a profile.php, I'd need to translate this three times, right?

- A solution given in the docs is using the gettext context, and have this pointing to the first template file where the string was used first, so I only need to translate that template's strings and the other two will "see" their translation threre. So in my fabricated example: 

//home.php:
__('Daytime phone number');

//login.php:
__('Daytime phone number','/site/templates/home.php');

//profile.php:
__('Daytime phone number','/site/templates/home.php');

So I only need to look for the translations of /site/templates/home.php in the translation tool and the other occurances of that string will be taken care for.

This now brings me to the idea of creating a php file in, say,  "/site/language/strings.php".

So what I can now do (but what feels kind of hacky to me…?), I use all the frequently used strings of my several template files in this "strings.php" file, wrapped in their language functions like __('translate me').

in _init.php or maybe in config.php I store this file's path for the context:

$i18lctx = '/site/templates/language/strings.php';

And now I can use the transalatable strings in several template/php files like this

// in home.php, in archive.php etc
__('Hello pilgrim',$i18lctx);

In PWs admin interface I'll have all the strings in one place: the strings.php (?textdomain=site--templates--language--strings-php).

Is this the right way to go about it or am I overlooking a basic fact (maybe like, dude, this is what the language packs are for)?

Cheers,

Tom

  • Like 4

Share this post


Link to post
Share on other sites

I think it's just fine using strings.php if it helps you - actually I'm using this right now, the only difference is that I named it "_strings.php", to avoid showing up as a template file.

Another simple solution can be found here, making a dedicated page for strings:

https://processwire.com/talk/topic/10443-how-to-do-this-global-vars/

  • Like 1

Share this post


Link to post
Share on other sites

I use a similar solution to a _strings.php file, and include it from my _init.php file (prependTemplateFile), so that it's available to all templates. But I bundle all the translated values into a new function (which I'll call _t(), but you could name it whatever you want). So you can call upon that _t() function anywhere that you'd call a __() function. For instance, in your /site/templates/_strings.php file...

function _t($label) {
  static $labels = null;
  if($labels === null) $labels = array(
    'Yes' => __('Yes'),
    'No' => __('No'),
    'Maybe' => __('Maybe'), 
    'And so on...' => __('And so on...')
  );
  return isset($labels[$label]) ? $labels[$label] : $label;
}

From there, you can replace any __('label') call with _t('label'). In this manner, you only need to translate your _strings.php file, and all the other template files can use the translated labels. For the cases where you need to translate text that only exists in a particular file, then you'd continue to use the __() function as usual.

  • Like 7

Share this post


Link to post
Share on other sites

I'm using almost the same setup, but my "t" function handles context too. The good thing is that _strings.php can be copied to your next projects too.

function t($text, $context = 'General', $textdomain = '/site/templates/_strings.php') {
    return _x($text, $context, $textdomain);
}

_strings.php:

// Search
_x('Search site', 'Search');
_x('No matches', 'Search');

// Forms
_x('From', 'Forms');
_x('From email', 'Forms');
_x('To', 'Forms');
...
  • Like 12

Share this post


Link to post
Share on other sites

hi,

thanks for the answers, I think i'll adapt this 't' function concept to my project.

this removes the 'hacky' feel of my approach with it's duplicate level of __('foo') functions, in _string.php and the template files. :)

cheers

tom

Share this post


Link to post
Share on other sites

tpr's solution is better than the one I posted. To take it a step further, those _x() functions never even need to execute. They can simply be contained in a PHP comment, as they only need to be visible to the language parser, which parses the files directly and doesn't execute the with PHP. So you could do this:

/******************************************* 
Intentionally commented out

​// Search_x('Search site', 'Search');
_x('No matches', 'Search');

// Forms
_x('From', 'Forms');
_x('From email', 'Forms');
_x('To', 'Forms');
...

*******************************************/

Of course the actual t() function should not be commented out though. 

  • Like 5

Share this post


Link to post
Share on other sites

To take it a step further, those _x() functions never even need to execute. They can simply be contained in a PHP comment

Indeed! Thanks for this extra step! :)

  • Like 2

Share this post


Link to post
Share on other sites

And one more:

function n($singular, $plural, $count) {
    echo t(_n($singular, $plural, $count));
}

This handles translations of singular/plural nouns, using the earlier introduced "t" helper.

Of course strings have to be listed in "_strings.php" to be translatable in the admin.

(I had to use "echo" instead of "return", probably because the template engine I'm using)

Usage:

n('minute', 'minutes', $page->count_of_something)

Using "/*!" instead of "/**" will prevent addition of stars when hitting new lines in IDEs:

/*!
Intentionally commented out

GENERAL
_x('minute', 'General');
_x('minutes', 'General');

SEARCH
_x('Search site', 'Search');
_x('No matches', 'Search');

 *******************************************/
  • Like 1
  • Thanks 2

Share this post


Link to post
Share on other sites

Hello,

I have the following structure in my project:

  • _head(which includes _head)
  • _header
  • _foot

I made a translation like echo "".__("Live long and prosper!","/site/templates/_header.php").""; but my website gives a "ERR_EMPTY_RESPONSE". I premuse that the problem is on the translation ou using translation in this template.

Anyone have a clue what it might be?

Best Regards

Share this post


Link to post
Share on other sites

This error is rather caused by the server and not your code (at least that's what I found on Google). 

Does the error go away if you remove that line?

Btw you could echo the translation in a simpler way:

echo __("Live long and prosper!", "/site/templates/_header.php");

Share this post


Link to post
Share on other sites

Hello,

Yes, if i remove the line the error goes away. 

And if i ignore _header template and make the translations only at _head template, there is no error anymore. It is beacause i am using a diferent template, from _head and _foot with "_" ?

regards.

Share this post


Link to post
Share on other sites

My solution was following:

function t($text) {
     
return include(wire('config')->paths->templates . '_translations.php');
}

_translations.php:

<?php 

$translations = [];

$translations[$text] = _x('String', 'General');

return $translations[$text];

This to avoid actual function file to be translatable at any point + better access for strings overall.

EDIT: Actually, this was good idea, but ain't working :) Sorry about posting, back to drawing board.

Share this post


Link to post
Share on other sites

Hi,

seems i am missing something. The strings to translate (from file _string.php) shows up in the admin language template and are being translated. But no change appears (or even getting errors) if i switch the language in the frontend. The pages are simply outputs whats being plain written in the template file, e.g the default language string. Maybe one of yours is so kind to confirm the following steps i did so far or - even better - give a hit where i go wrong, e.g. what i forgot to consider  :huh: .

I got a _init.php file which is prepended before any other file (config.php). This init file includes the related files:

// Shared functions
include_once("./_func.php");

// Translation strings
include_once("./_strings.php");

_func.php contains the function

function _t($text, $context = 'Generic', $textdomain = '/site/templates/_strings.php') {
  return _x($text, $context, $textdomain);
}

while _strings.php contains the translation files

/*!

_x('Soziale Netzwerke', 'Footer');
_x('Sprachwahl', 'Footer');

*/

Within template home.php for example those strings are printed like this:

<?php echo _t('Soziale Netzwerke');?>

Any hint what i am missing here is much appreciated!

Thanks a lot in advance, regards

Share this post


Link to post
Share on other sites

I guess you simply forgot the context:

<?php echo _t('Soziale Netzwerke', 'Footer');?>

If you set no context, the default will be used ('Generic' in your example). So if you wouldn't like to write the context in your php files, you should add strings to the Generic context in your _strings.php:

// _strings.php:
_x('Soziale Netzwerke', 'Generic');

// then you can omit context in templates:
<?php echo _t('Soziale Netzwerke');?>

Read more on context here:

https://processwire.com/api/multi-language-support/code-i18n/#context

Share this post


Link to post
Share on other sites

Hi tpr,

I guess you simply forgot the context:

<?php echo _t('Soziale Netzwerke', 'Footer');?>

If you set no context, the default will be used ('Generic' in your example). So if you wouldn't like to write the context in your php files, you should add strings to the Generic context in your _strings.php:

Thank you very much for your answer. I assumed to overlooked something. And here we go, the context was missing. All is doing fine now. Thx!

Share this post


Link to post
Share on other sites

tpr method is really good for translation strings across templates.

However, with using this method , in a situation of not just translated a one to two words label, but a medium long string with html tag

Let's say an message to user

In my current implementation, i have this translation code

$registration_success_message = html_entity_decode(__("Thank you for registration. <br/><br/>Please wait for account approval from administrator."));

in the template ,

i will echo $registration_success_message;

Share this post


Link to post
Share on other sites

You can use a page dedicated to translations. Just create multilanguage text or textarea fields and simply echo their content as usual.

Share this post


Link to post
Share on other sites

support plain text string and string with html tag

function _t($text, $context = 'general', $textdomain = '/site/templates/_strings.php') {
    return html_entity_decode(_x($text, $context, $textdomain));
}
  • Like 3

Share this post


Link to post
Share on other sites

I see, thanks. I will think about it if it's a good practice, I use the same thing in my Latte module.

Share this post


Link to post
Share on other sites

@adrianmak just needed the html_entity_decode in the current project so I'll add this to my module, thanks! :)

Share this post


Link to post
Share on other sites
On 18.7.2015 at 3:33 PM, ryan said:

I use a similar solution to a _strings.php file, and include it from my _init.php file (prependTemplateFile), so that it's available to all templates. But I bundle all the translated values into a new function (which I'll call _t(), but you could name it whatever you want). So you can call upon that _t() function anywhere that you'd call a __() function. For instance, in your /site/templates/_strings.php file...


function _t($label) {
  static $labels = null;
  if($labels === null) $labels = array(
    'Yes' => __('Yes'),
    'No' => __('No'),
    'Maybe' => __('Maybe'), 
    'And so on...' => __('And so on...')
  );
  return isset($labels[$label]) ? $labels[$label] : $label;
}

From there, you can replace any __('label') call with _t('label'). In this manner, you only need to translate your _strings.php file, and all the other template files can use the translated labels. For the cases where you need to translate text that only exists in a particular file, then you'd continue to use the __() function as usual.

Hi @ryan

I have used this way to translate all of my strings and it works ("has worked") good. But now I have encountered something. A Client of mine called me and said that all the translations from the _string.php for the default languages were gone when he had added the translation for two other strings. The new changed Strings weren't gone but all other were it. Do you perhaps know what could cause such a dangerous action? The _strings.php file has 80-90 Translations at the moment.

 

Greetings

Orkun

Share this post


Link to post
Share on other sites

Hello guys. I just found this topic while searching for a smarter way to translate the whole site using a single file instead of having repetitive translations in different templates. Tried to reproduce @tpr and @felic approach of using strings file but things got messed up.

If I add:

// Translation strings
include_once("./_strings.php");

to my _init.php that is prepended in the config.php I am seeing the content of the file in my header

LANG-FUNCTION-ERROR.thumb.png.6d1e0482177e938451cf1118a54c15a1.png

As far as I remove the include from _init.php all the styles come back promptly.

Trying to figure out what is wrong with the setup that worked for others, I decided to remove the include from _init.php again and add manually the strings.php file by going to the language administration and from there after clicking on Find Files To Translate I clicked on Enter file to translate at the bottom and added manually the path to my language file: /sites/templates/languages/strings.php

After that I went back to the language translation and added my strings and voila, it all started working promptly.

Now this raises a few questions for me:

1. What am I doing wrong to see the include in the header?

2. Do the include of strings.php in _init.php only allowing the file to be automatically found and listed in the translation files or there is another purpose?

3. Is is OK to leave the translation files out of the _init.php and add it manually during the profile work or there are some drawbacks I am not seeing yet?

Share this post


Link to post
Share on other sites

Are you sure there's an opening php tag in the strings php file? 

I include that file in ready.php but  I don't think that makes a difference. 

Share this post


Link to post
Share on other sites

Well I am sure that it is commented and tried to recreate the file several times. Here is the content of it:

/*

// Footer.php
_x('CONTACT INFO', 'Generic');
_x('COMPANY LINKS', 'Generic');
_x('ABOUT US', 'Generic');

// About.php
_x('OUR HISTORY & FACTS', 'Generic');
_x('LEADER IN THE REAL ESTATE MARKET SALES SINCE', 'Generic');
_x('GET A QOUTE', 'Generic');

*/

That is what questioned me, why I see the comments in the header and that messes up the divs etc., however as soon as I remove the include it works if I manually add the file path for translation. I checked for some bizzaire code in the header but it is all good there so no explanation why would commented block appear...

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...