Yii2 translation does not work in config/params - internationalization

I have the following config/params.php in my yii2-basic-app:
<?php
$siteName = Yii::t('app','Site Name'); //previously, this value had been placed directly in the array just a try to make it available to the translation
return [
'adminEmail' => 'admin#example.com',
'siteName' => $siteName,
'textToPrint' => null,
'meta-description' => $siteName,
];
The message Site Name is already has a translation in #app/messages/ar/app.php and the translation is working fine on the website.
However, when I try to use meta tag description in the main layout like the following:
<meta name="description" content="<?= Yii::$app->params['meta-description'] ?>" />
So, in any view, if I have set a value to Yii::$app->params['meta-description'] it should be printed out in the layout while when there is no any supplied value to it, it should print the initial value defined in config/params.php.
The problem is, the initial value is printed without translation. This is issue may be solved by translating the string in the main layout as the following:
<meta name="description" content="<?= Yii::t('app',Yii::$app->params['meta-description']) ?>" />
Due to the above solution I have two questions:
Why the string did not be translated in the config/params.php?
Does the heavy use of Yii::t() with many untranslated strings, (in my case, when I decide to override the value Yii::$app->params['meta-description'] in a view), has any performance issue?

Answers:
Because config/params.php file will merge with main config before initialization of main application. For translation will used \yii\i18n\I18N component.
Yii2::t() is not heavy method. But if you have any problems with performance, you can override this method and execute Yii:$app->getI18n()->translate() only for existing strings, or enable cache this values.

You can use something like this
public static function translateParams($param)
{
if (is_array($param)) {
array_walk($param, function (&$value) {
$value = \Yii::t("app", $value);
});
return $param;
} else {
return \Yii::t("app", $param);
}
}

Related

Tagged Blade component with variable name

i have a view where a different tagged component should be rendered depending by the value of a variable where the name is stored. For example
#if( $a['type'] == 'component' )
"<x-{$a['name']} />"
#endif
But i can't find how to do it the right way, because using brakets {{ }} will also print them on the page ( before and after the component ).
The component class also has some function that is being called, so the #component directive would only solve a part of the problem.
I might have figured out the solution and i will post it in here for reference. It currently works but i can't say it won't give me some trouble later on, In case you find a better approach i will be happy to have a look.
After having created a few blade components as usual
php artisan make:component MyComponent1
php artisan make:component MyComponent2
php artisan make:component MyComponent3
and having declared all needed properties and methods, you can either include the components inside a view the regular way
<html>
<head></head>
<body>
#if($somethingHappens)
<x-my-component1 a="" b="" :c="$c" class="" />
#elseif ($somethingElseHappens)
<x-my-component2 a="" b="" :c="$c" class="" />
#else
<x-my-component3 a="" b="" :c="$c" class="" />
#endif
</body>
</html>
Or, in case you would like more flexibility deciding what component should be used at runtime and generate the component tags somewhere else outside the view, i have found this solution
//some code.....
return('myview')->with([
'type' => 'component',
'component' => '<x-my-component3 a="" b="" :c="$vars[\'c\']" class="" />',
'vars' => [ 'c' => 'somevalue' ]
]);
#################
//myview.blade.php
<html>
<head></head
<body>
#php
if($type == 'component')
echo compileStringComponent(
$component,
$__env,
$vars
);
#endphp
</body>
</html>
################
//file containing the function
use Illuminate\View\Factory as ViewFactory;
//This function takes the whole tagged component as string and returns the corresponding html
function compileStringComponent(string $component, ViewFactory $__env, $vars = null )
{
$compiled = Blade::compileString($component);
ob_start();
try {
eval('?>'.$compiled);
} catch (\Exception $e){
ob_get_clean();
throw( $e);
}
$content = ob_get_clean();
return $content;
}
A few notes:
1) Blade::compileString returns a compiled string to be evaluated, and inside the code there are a few references to the $__env variable which is an instance of Illuminate\View\Factory and exists inside the view already. This means that if the function is called outside the view, the $__env variable must be passed to the caller
2) The $vars array is needed in case data is passed to the component through the :attributes for the same reason as above, because those variables will not exist inside the caller and must be passed to it
3) ob_start() and ob_get_clean() are used to avoid sending incomplete views to the user in case any error arises.
I hope it will helps somebody

Where to define a filter function for a form field in my Joomla component's preferences

I am creating a component in Joomla 2.5. This component has some options that are defined in its config.xml, so they can be set in the preferences of the component. Now I would like to apply a filter to one of these option fields, using the attribute filter="my_filter".
In the source code of JForm I saw the following lines at the very end of the implementation of JForm::filterField():
if (strpos($filter, '::') !== false && is_callable(explode('::', $filter)))
{
$return = call_user_func(explode('::', $filter), $value);
}
elseif (function_exists($filter))
{
$return = call_user_func($filter, $value);
}
That's what I needed for using a filter function defined by myself!
I managed to do this for form fields used in the views of my component. I defined the filter function as MyComponentHelper::my_filter(), where MyComponentHelper is a helper class which I always load in the very base of my component. And in the form's xml I added filter="MyComponentHelper::my_filter" to the fields that have to be filtered. However... when I am trying to apply the filter function to a form field in my component's preferences, I am not in my own component, but in com_config instead, so my helper class is not available!
So, therefore, my question: where to define my own filter function in such a way that it can be found and called by JForm::filterField() in com_config?? Help is very much appreciated.
May be it is too late, but this topic is only I found about that trouble. May be my solution will be helpfull to someone.
1) Add to tag of .xml form file the attribute 'addfieldpath' like this:
<fieldset name="basic" addfieldpath="PATH_TO_MY_EXTENSION/models/fields">
2) Modify filtered field description like this:
<field
name="MY_FIELD_NAME"
type="myfildtype"
label="MY_FIELD_LABEL"
description="MY_FIELD_DESC"
filter="JFormFieldMyFieldType::filter"
/>
3) Create the file 'PATH_TO_MY_EXTENSION/models/fields/myfildtype.php':
<?php
defined('JPATH_PLATFORM') or die;
JFormHelper::loadFieldClass('text'); // or other standard Joomla! field type
class JFormFieldMyFieldType extends JFormFieldText // or other standard Joomla! field type class
{
protected $type = 'MyFieldType';
public static function filter($value)
{
// filter code
return $value;
}
}
I had to deal with the same issue today. Here is what I did.
Our form field looks like this:
<field name="verwaltungskosten" type="text" class="form-control" size="40" label="Verwaltungskosten" labelclass="col-sm-2
compojoom-control-label"
filter="MyComponentFilterDouble::filter" required="true"/>
As you can see we have a filter. We've specified
MyComponentFilterDouble as class and filter as a method of this class.
If you have a look at libraries/joomla/form/form.php in the
FilterField function toward the end you'll see that the code will try
to execute our custom filter. Now here comes the tricky part. How does
Joomla know where our filters are located? Well, it doesn't! We have
to load our filters in advance. JForm doesn't come with a utility
class that could load a custom filter. I've decided to load our
Filters in our model in the getForm function. As you know each model
that extends from JModelAdmin should have a getForm function. This
function makes sure that we are loading the correct form from a .xml
file. So in this function just before I load the form I did:
JLoader::discover('MyComponentFilter', JPATH_ADMINISTRATOR . '/components/com_mycomponent/models/forms/filters');
The discover method will make sure to auto load our class when we need
it. This way it will be available to our form.
And there we go! Now when our model validates the form. It actually
always first performs filtering on the data. Now in our custom filter
we can modify the data and pass it back for validation. It's that
easy!
The above text is in quotes because I took it from my blogpost about that same issue over here: https://compojoom.com/blog/entry/custom-filtering-for-jform-fields
I think what you're asking about is actually adding custom validation to one of your form fields. If that's the case you actually need to be looking at adding server-side validation in addition to adding configuration. Pay particular attention to the 'addrulepath' in the example under the heading "Using configuration parameters as default value". You'll most likely end up extending JFormRule, of which I've included a very stripped-down example below.
<?php
/** headers */
defined('JPATH_PLATFORM') or die; // Joomla only
class JFormRuleCustom extends JFormRule
{
public $type = 'Custom';
public function test(&$element, $value, $group = null, &$input = null, &$form = null) {
return /* true for passed validation, false for failed validation */
}
}
When you've got that down you can add the validation "custom" to your form fields like so:
<field
name="pw1"
type="password"
label="COM_NEWUSER_UPDATE_LABEL_PASSWORD1"
description="COM_NEWUSER_UPDATE_DESCRIPTION_PASSWORD1"
message="COM_NEWUSER_UPDATE_ERROR_PASSWORD1"
size="40"
required="true"
validate="custom"
minlength="5"
maxlength="20"
specials="!##$%^&*"
/>
Hopefully that answers your question and didn't go totally off-topic.

Laravel 4: if statement in blade layout works strange

Could someone explain me why I get blank screen with printed string "#extends('layouts.default')" if I request page normally (not ajax)?
#if(!Request::ajax())
#extends('layouts.default')
#section('content')
#endif
Test
#if(!Request::ajax())
#stop
#endif
I'm trying to solve problem with Ajax, I don't want to create 2 templates for each request type and also I do want to use blade templates, so using controller layouts doesn't work for me. How can I do it in blade template? I was looking at this Laravel: how to render only one section of a template?
By the way. If I request it with ajax it works like it should.
Yes #extends has to be on line 1.
And I found solution for PJAX. At the beginning I was not sure this could solve my problem but it did. Don't know why I was afraid to lose blade functionality if you actually can't lose it this way. If someone is using PJAX and needs to use one template with and without layout this could be your solution:
protected $layout = 'layouts.default';
public function index()
{
if(Request::header('X-PJAX'))
{
return $view = View::make('home.index')
->with('title', 'index');
}
else
{
$this->layout->title = 'index';
$this->layout->content = View::make('home.index');
}
}
Try moving #extends to line 1 and you will see the blade template will render properly.
As for solving the ajax problem, I think it's better if you move the logic back to your controller.
Example:
…
if ( Request::ajax() )
{
return Response::eloquent($books);
} else {
return View::make('book.index')->with('books', $books);
}
…
Take a look at this thread for more info: http://forums.laravel.io/viewtopic.php?id=2508
You can still run your condition short handed in the fist line like so
#extends((Request::ajax())?"layout1":"layout2")

Joomla editor strips tags

I'm trying to create a custom component in Joomla 2.5 and struggling to get it to stop it stripping all html tags out of the editor field - links, new lines, p tags - the full works. The form field is below:
<field
name="post"
type="editor"
label="COM_HELLO_WORLD_EDITOR_LABEL"
description="COM_HELLO_WORLD_EDITOR_DESC"
class="inputbox"
filter="JComponentHelper::filterText"
required="true"
default=""
/>
Clearly there are many many posts about this around both SO and Joomla forums. However they generally seem to have two clear themes.
Tiny MCE Settings. I've checked after setting my default editor to "None" (i.e. just a text area) and the tags are all still stripped
Joomla Text filter settings. I'm logged in as a Global Admin with the super users set to "no filtering"
I'm overriding the model's save function for this with:
function store()
{
$row =& $this->getTable();
$input = new JInput();
$data = $input->getArray($_POST);
//Sets Users id as current logged in user if not set
if(!$data['jform']['post_user']) {
$data['jform']['post_user']=JFactory::getUser()->id;
}
// Bind the form fields to the post table
if (!$row->bind($data['jform'])) {
$this->setError($this->_db->getErrorMsg());
return false;
}
// Make sure the hello is valid
if (!$row->check()) {
$this->setError($this->_db->getErrorMsg());
return false;
}
// Store the hello table to the database
if (!$row->store()) {
$this->setError($this->_db->getErrorMsg());
return false;
}
return true;
}
My gut instinct is that it's to do with JInput stripping HTML tags. But even adding in the extra line into the save file $data['jform']['post']=$input->getHTML('post'); nothing happened. So I'm not really sure where to go from here. Any ideas?
UPDATE
Just to clarify an issue quickly - I want to use the preset Joomla 'Text Filter' Settings under 'Global Configuration' rather than manually setting each tag in the component!
UPDATE 2
I added filter="raw" to the editor form field. I now see the html <p> tags when I dump out the variable $_POST['jform']['post'], null, 'HTML'). However then when applying just a simple JInput Filter function - let alone applying the Joomla Config values - I'm getting null.
$input = new JInput();
$data = $input->getArray($_POST);
$data['jform']['post']=$input->get($_POST['jform']['post'], null, 'HTML');
Is the sentence here "HTML - Returns a string with HTML entities and tags intact, subject to the white or black lists in the filter." describing the JInput HTML filter referring to the Global Config Text filter settings? Just to confirm?
Try something like this
$input_options = JFilterInput::getInstance(
array(
'img','p','a','u','i','b','strong','span','div','ul','li','ol','h1','h2','h3','h4','h5',
'table','tr','td','th','tbody','theader','tfooter','br'
),
array(
'src','width','height','alt','style','href','rel','target','align','valign','border','cellpading',
'cellspacing','title','id','class'
)
);
$postData = new JInput($_POST,array('filter' => $input_options));
First array it is allowed tags, second array it is allowed attributes.
What is this about? filter="JComponentHelper::filterText"? Did you write a custom filter?
The default filtering like most things in Joomla (also acl for example) is very strict so that if you get xss from not filtering it's a deliberate choice you've made not a security risk in the core. But your core filtering should be being applied ... except that you seem to have perhaps overridden with the unknown filter. So I suspect given this unknown filter it's falling back to very string.
Quite some time later, but just for the record, for anyone encountering the same problem, here my solution.
For me this problem was immediately solved by using JRequest instead of JInput. I believe it's deprecated, but it is still used by Joomla 2.5.14 (most up-to-date Joomla 2.5 at this moment) in the save() function of JControllerForm.

How can I return actual JSON using Drupal?

I'd like to implement a simple AJAX function locally that allows me to autocomplete node titles of already existing nodes as the user types. To that end, I need the ability to have an API that I can search on node titles. The problem is that when I output raw JSON, it comes surrounded by tags. So, no matter what I do, I keep getting...
<html>
<head>
</head>
<body>
<pre style="word-wrap: break-word; white-space: pre-wrap;"> {json here}</pre>
</body>
</html>
I've tried implementing a custom page template that only outputs content already, that produced the same results. Here is how I am currently doing this, in my module file...
<?php
/**
* Implementation of hook_menu()
*/
function content_relation_menu() {
$items = array();
$items['api'] = array(
'title' => 'Search',
'page callback' => 'content_relation_get',
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
return $items;
}
function content_relation_get($term = '') {
drupal_add_http_header('Content-Type', 'application/javascript; utf-8');
$var = json_encode(
db_query("SELECT nid,title FROM {node} WHERE title LIKE :title LIMIT 5", array(":title" => $term.'%'))->fetchAll()
);
echo $var;
exit(0);
}
How can I return JUST raw JSON?
The 'Drupal' way is using drupal_json_output() and drupal_exit().
$data = db_query("SELECT nid,title FROM {node} WHERE title LIKE :title LIMIT 5", array(":title" => $term.'%'))->fetchAll();
drupal_json_output($data);
drupal_exit();
UPDATE
I've just put your code, as is, into a module and all I get when requesting http://site.com/api is the expected JSON, there are no tags. The problem won't be anything to do with Drupal, more likely to do with server/browser configuration.
This link may help:
What do browsers want for the Content-Type header on json ajax responses?
This actually DID output raw JSON - Chrome was adding the html wrapping. Viewing the output in command line cURL showed that this did output raw JSON.
Take out the exit(0); and it should work. If your page callback doesn't return anything then the normal theme handlers don't get called so you get raw output.
That said, due to the rather poor performance of Drupal, for decent response times you're better off making a small standalone script that talks to the drupal DB, so you don't pay the rather heavy startup costs of a drupal request when you don't need of that functionality.

Resources