Jump to content

Problem with translatable strings that are included through a ‘file’ type field


bytesource
 Share

Recommended Posts

Hi,

I have a field sidebar_content of type file that I use to select different snippets of code like the following:

/site/templates/snippets/sidebar/content/projects_page_promotion.inc
<h5>Information</h5>
<section class="infobox">
 <p><?php echo __("Make sure to visit our new 'Projects' page"); ?></p>
</section>


The snippets are included in the template as follows:

<?php
if ($page->sidebar_content) {
 foreach($page->sidebar_content as $content) {
    echo "<li>";
    include($content->filename);
    echo "</li>";
 }
}
?>


This approach works, but when the locale changes

if($config->httpHost == 'es.example.com') {
   $user->language = $languages->get("spanish");
}


the sentence in the above snippet

<?php echo __("Make sure to visit our new 'Projects' page"); ?>

is still shown in English, while translatable strings in other template files output the Spanish versions correctly.

I would be glad if someone could point me to my error or maybe suggest a better approach.


Cheers,

Stefan

Link to comment
Share on other sites

I have a field sidebar_content of type file that I use to select different snippets of code like the following:

I am confused about how your includes are being done. You mentioned you are using a File field and including them, which sounds concerning from a security standpoint. But the snippet you mentioned (/site/templates/snippets/...) is not in the path where file uploads go, so I'm confused on that point. 

As for why they aren't translating--have you specifically translated them? By that I mean, did you go to Setup > Languages > [some language] > Translate New File > Enter filename: /site/templates/snippets/sidebar/content/projects_page_promotion.inc ?

If you have translated them, then the translation will only work so long as the file stays in the location that you translated it from. That location is called the "textdomain", and it's the primarily way that set of translations relates to a file. So if you translated the above file, and then uploaded to your site somewhere else, it would not continue to be translated.

Link to comment
Share on other sites

I am confused about how your includes are being done. You mentioned you are using a File field and including them, which sounds concerning from a security standpoint. But the snippet you mentioned (/site/templates/snippets/...) is not in the path where file uploads go, so I'm confused on that point. 

I include each snippet from the admin choosing its file path from the sidebar_content field of type file. No person other than my is allowed to include these files. 

If you have translated them, then the translation will only work so long as the file stays in the location that you translated it from. That location is called the "textdomain", and it's the primarily way that set of translations relates to a file. So if you translated the above file, and then uploaded to your site somewhere else, it would not continue to be translated.

I guess that might be the problem. The original snippets/files are stored in  /site/templates/snippets/sidebar/content/, but after uploading they are pulled from /site/assets/files/a_number/.

Link to comment
Share on other sites

Apparently my solution did not work out. I also tried including the snippets into the sidebar area via page references, where each page had a template infobox that just rendered the body field of that page. However, this didn't work out either, as the body field often contains HTML and PHP code.

Is there a more elegant way of choosing and displaying different sidebar content?

Cheers,

Stefan

Link to comment
Share on other sites

I'm confused by your last statement - you cant have a field in ProcessWire containing PHP code. It would just spit it out as text.

Even if you put PHP into a text field the only way you could parse the PHP is with eval() and that's really not recommended.

Or am I misunderstanding?

Link to comment
Share on other sites

I guess that might be the problem. The original snippets/files are stored in  /site/templates/snippets/sidebar/content/, but after uploading they are pulled from /site/assets/files/a_number/.

You could just perform the translation from its final location, rather than it's temporary location. But the truth is that anything that allows one to upload code or files that will be executed on the server is considered a security hole. It's true that it's probably fine if you are the only one that can write or upload that code. But it's also far from a best practice, and ProcessWire is written towards enforcing best practices, which is why it's not making it easy here. 

One way to do it that would be workable would be to keep your files in the original location (off /site/templates/) and use your fields to refer to them rather than pull code from them. For instance, you might have a text field where you type "projects_page_promotion" in it, and your template file automatically includes the file matching the name in /site/templates/snippets/sidebar/content/.

To take it further, you could make it a Page reference field, so that they could be selectable and even draggable/droppable (via an asmSelect field). Let me know if I can describe more detail on that. There are all kinds of possibilities here. But it would require you to maintain the best practice of keeping the actual code out of your site's content and as part of your site's development files. 

Link to comment
Share on other sites

I agree that uploading any code that gets executed on the server is always a bad idea. I just couldn't come up with a better solution. 

That's why I am especially gratefull for your suggestions. Following your first approach I solved the problem as follows:

1) Added field sidebar_content of type textarea to the respective templates. sidebar_content contains the names of the snippet files to be included (please see attachment). 

2) Template code:

<?php
// Variables to be set:
// $content
// $sidebar

include_once("./helpers.inc");

// content
$t_content  = new TemplateFile(wire('config')->paths->templates . 'snippets/pages/_contact.php');

$content = $t_content->render();

// sidebar
$side    = new TemplateFile(wire('config')->paths->templates . 'snippets/sidebar/sidebar.php');
$sidebar = $side->render();

include("./main.inc")
?>

3) Code of sidebar.php:

<?php
$filenames = $page->sidebar_content;
if ($filenames) {
  $filenames = explode("\n", $filenames);
  foreach ($filenames as $name) {
    $name = trim($name);
    echo "<li>";
    $t = new TemplateFile(wire('config')->paths->templates . "snippets/sidebar/content/" . $name . ".php");
    echo $t->render();
    echo "</li>";
  }
}
?>
 
 
While the above approach is working, I am not sure if it is in any way ideomatic. Any suggestions, especially regarding the php code are highly welcome!
 
Cheers, 
 
Stefan
 
 

post-855-0-93054700-1358065866_thumb.jpg

Link to comment
Share on other sites

I think that's a definite improvement. If your need allows it, you might want to prevent the inclusion of slashes so that someone can't have it pull in PHP files outside of the directory where you are allowing them. 

$name = $sanitizer->pageName($name); 

That will replace anything that's not in this set of characters: "-_.a-z0-9", with hyphens. That adds some reasonable security here. 

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...