I don't know if this is a bug or a mistake on my end but basically I followed the Yii2 documentation to setup i18n translations for modules. The following snippet is directly copy pasted from the Yii2 guide.
public function init()
{
parent::init();
$this->registerTranslations();
}
public function registerTranslations()
{
Yii::$app->i18n->translations['modules/users/*'] = [
'class' => 'yii\i18n\PhpMessageSource',
'sourceLanguage' => 'en',
'basePath' => '#app/modules/users/messages',
];
}
public static function t($category, $message, $params = [], $language = null)
{
return Yii::t('modules/users/' . $category, $message, $params, $language);
}
According to the guide I should call it like this:
Module::t('validation', 'your custom validation message')
However, Yii2 tries to load the the 'validation.php' from the wrong location. This is the output of the debugger:
The message file for category 'modules/users/validation' does not exist: /Applications/MAMP/htdocs/.../domains/localhost/public_html/.../backend/modules/users/messages/en/modules/users/validation.php
From what I understand, it should be looking for modules/users/message/<lang>/validation.php instead, which makes a lot more sense than what it is looking for right now.
What am I doing wrong?
Thank you in advance.
You should simply add a filemap param, e.g. :
public function registerTranslations()
{
Yii::$app->i18n->translations['modules/users/*'] = [
'class' => 'yii\i18n\PhpMessageSource',
'sourceLanguage' => 'en',
'basePath' => '#app/modules/users/messages',
'fileMap' => [
'modules/users/validation' => 'validation.php',
],
];
}
Read more : http://www.yiiframework.com/doc-2.0/guide-tutorial-i18n.html#translating-module-messages
EDIT : As stated in Yii2 guide, if you want to remove filemap, your validation.php file should be in modules/users/messages/[lang]/modules/users/validation.php.
Instead of configuring fileMap you can rely on convention which is to use the category name as the file name (e.g. category app/error will result in the file name app/error.php under the basePath.
Related
I implemented CakePHP4 authentication following this:
https://book.cakephp.org/4/en/tutorials-and-examples/cms/authentication.html
It worked, then I need to use my custom PasswordHasher to satisfy the client requirements. I couldn't find any tutorial to do that, but figured out the following code works.
In Application.php:
public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface {
// ....
$authenticationService->loadIdentifier('Authentication.Password', [
'fields' => [
'username' => 'username',
'password' => 'password',
],
'passwordHasher' => [
'className' => 'Authentication.MyCustom',
]
]);
The problem is that I need to put MyCustomPasswordHasher.php file in vendor\cakephp\authentication\src\PasswordHasher in order to make this work. Of course I don't want to put my own code under vendor directory.
Temporarily, I created and used src\Authentication\PasswordHasher directory and forced to make it work by doing this:
spl_autoload_register(function ($class) {
if (strpos($class, 'MyCustomPasswordHasher') !== false) {
require_once __DIR__ . '/' . str_replace(['\\', 'App/'], [DS, ''], $class) . '.php';
}
});
Is there any cleaner way to accomplish the purpose in CakePHP4? Where should I put custom codes?
Don't use plugin notation for the short name, pass only 'MyCustom', then it will look inside of your application, in the App\PasswordHasher namespace, so your class would accordingly go into
src/PasswordHasher/MyCustomPasswordHasher.php
Alternatively you can always pass a fully qualified name, meaning you could put your class wherever you want, as long as the composer autoloader can resolve it:
'passwordHasher' => [
'className' => \Some\Custom\Namespaced\PasswordHasher::class,
]
i have a little problem with smarty extension for yii2.
I've created a new smarty function, and i've added the code into this file:
backend/vendor/yiisoft/yii2-smarty/src/Extension.php
public function __construct($viewRenderer, $smarty)
{
//other code
/* CUSTOM FUNCTION REGISTER */
$smarty->registerPlugin('function', 'test', [$this, 'functionTest']);
}
//this is the custom function
public function functionTest($params, $template){
return "Test custom funcion";
}
And i can use this custom function into my template like this {test} and all works fine.
Today i have update the yii2 to the 2.0.20 version, and obviously the Extension.php file was replaced, so i can't access anymore to the custom function.
My question is: How i can add a custom function for smarty in yii2?
I'll set the config array in this way:
//this is in backend/config/main.php
'view' => [
'renderers' => [
'tpl' => [
'class' => 'yii\smarty\ViewRenderer',
'pluginDirs' => ['#backend/saSmartyPlugin'],
'widgets' =>[
'functions' => [['test' => 'test'], ],
],
//'cachePath' => '#runtime/Smarty/cache',
],
],
],
and the into saSmartyPlugin folder i insert my test.php file like this:
<?php
class Test{
function functionTest($params, $template){
return "Test custom funcion";
}
}
But i get this error:
Smarty: Undefined class 'test' in register template class
I agree with Muhammad Omer Aslam, you should extend from backend/vendor/yiisoft/yii2-smarty/src/Extension.php in order to create Any new methods and be able to use them after update. After that you just write in your config file path to your extended class.
I'll find a solution thinking about #MuhammadOmerAslam and #SergheiLeonenco suggest me.
I write this answer for anyone who has this problem.
First i create my php file Test.php and i extend the Extension class of Smarty
namespace common\components;
use yii\smarty\Extension;
class Test extends Extension{
public function __construct($viewRenderer, $smarty){
parent::__construct($viewRenderer, $smarty);// call parent construct
$smarty->registerPlugin('function', 'bread', [$this, 'functionBreadcrumbs']);//register my custom function
}
//My custom function
function functionTest($params, $template){
return "Test custom funcion";
}
And i save this file into common/components/
After that i have modified my config.php file
'view' => [
'renderers' => [
'tpl' => [
'class' => 'yii\smarty\ViewRenderer',
'extensionClass' => 'common\components\Test'
],
],
],
],
I am trying to configure Yii2 url manager in a manner that if a controller name is skipped in url it should call the default controller for action. I have managed to achieve this without action parameter. But got stuck when using parameters in action name.
Here is my route config:
return [
'catalog/category/<alias:[\w-]+>' => 'catalog/default/category',
'catalog/<action:\w+>' => 'catalog/default/<action>',
];
Controller File:
namespace app\modules\catalog\controllers;
use yii\base\Controller;
use app\modules\catalog\models\Categories;
class DefaultController extends Controller
{
public function actionShopbydepartment()
{
$data['categories'] = Categories::findParentSubHierarchy();
return $this->renderPartial('shopbydepartment', $data);
}
public function actionCategory($alias = null)
{
die(var_dump($alias));
$data['category'] = Categories::findCategoryBySlug($alias);
return $this->render('category', $data);
}
}
when I access the following url it loads perfectly.
http://domain.com/index.php/catalog/shopbydepartment
But when i access the below url it called the right function but did not pass the $alias value:
http://domain.com/index.php/catalog/category/appliances
UPDATE:
I have used the following approach for module wise url rules declaration:
https://stackoverflow.com/a/27959286/1232366
Here is what i have in the main config file:
'rules' => [
[
'pattern' => 'admin/<controller:\w+>/<action:[\w-]+>/<id:\d+>',
'route' => 'admin/<controller>/<action>'
],
[
'pattern' => 'admin/<module:\w+>/<controller:\w+>/<action:[\w-]+>/<id:\d+>',
'route' => 'admin/<module>/<controller>/<action>'
],
],
the admin is working fine and this is my first module so rest of the rules are mentioned already
Well just to help other fellows I have retrieve the value of $alias using the following approach:
$alias = \Yii::$app->request->get('alias');
But definitely this is not an accurate answer of the question. I still didn't know what i am doing wrong that i didn't get the value using the approach mentioned in question.
It wirk!
[
'name' => 'lang_country_seller_catalog',
'pattern' => '<lang:\w+>-<country:\w+>/seller/catalog/<module>/<controller>/<action>',
'route' => 'seller/catalog/<module>/<controller>/<action>',
],
[
'name' => 'lang_country_seller_catalog_attributes',
'pattern' => '<lang:\w+>-<country:\w+>/seller/catalog/attributes/<module>',
'route' => 'seller/catalog/attributes/<module>',
],
Suppose I installed module Foo form a repository with composer. The module structure is like this:
- Foo
|- models
|- controllers
|- views
|- messages
|- config
Messages folder of Foo contains translation files of module. Now I want override some translation strings of Foo. From Yii2 i18n Documentation I tried to use fileMap property on configuration of translation component to map bar category to bar.php (instead of reading from app\modules\Foo\messages), but it does not have any effect on translations. My i18n component configuration is:
'i18n' => [
'translations' => [
'*' => [
'class' => 'yii\i18n\PhpMessageSource',
'fileMap' => [
'bar' => 'bar.php'
],
],
],
],
How do i achieve my goal?
If you are wanting to have translations for each module contained within the module, then you need to register the translations for that module. It can't be done simply from the config file. You probably already have this in your module file,, I just include for completeness. The code is copied from the documentation, and needs to be in your module file, so in app/modules/Foo.php
<?php
namespace app\modules\foo;
use Yii;
class Module extends \yii\base\Module
{
public $controllerNamespace = 'app\modules\foo\controllers';
public function init()
{
parent::init();
/** Register custom translations for this module **/
$this->registerTranslations();
}
public function registerTranslations()
{
/**This registers translations for the Foo module **/
Yii::$app->i18n->translations['modules/foo/*'] = [
'class' => 'yii\i18n\PhpMessageSource',
'sourceLanguage' => 'en-US',
'basePath' => '#app/modules/foo/messages',
/**Tells yii where to find the translations for validation and form categories **/
'fileMap' => [
'modules/foo/validation' => 'validation.php',
'modules/foo/form' => 'form.php',
...
],
];
}
public static function t($category, $message, $params = [], $language = null)
{
return Yii::t('modules/users/' . $category, $message, $params, $language);
}
}
In your case it doesn't look like you need to provide file mapping.You could simply use this format for your files
[[basePath]]/LanguageID/CategoryName.php
Unfortunately I can't seem to find a list of the available categories.
If you then want to override some of the module translations you will need to specify the category to be used, like this in your config file. It specifically overrides the modules/foo/bar category.
'i18n' => [
'translations' => [
'modules/foo*' => [
'class' => 'yii\i18n\PhpMessageSource',
'basePath' => '#app/messages',
],
],
],
Your translation file needs to follow a folder structure like that in the translation description, so in the above example it would be
app/messages/ [language code] /modules/foo/bar.php
Otherise, you can use fileMap to map to different locations, like if your bar.php file is in app/messages/[language code]
'fileMap' => [
'modules/foo/bar' => 'bar.php'
]
I have a multilanguage website in Laravel 4.2, and would like to send an email notification to the admins in a specified language using the lang files.
How can I call Lang::get('group.key') specifying the needed language ?
Thank you for your help !
Edit: existing code: (the lang items are option1, option2, .., option6)
class EmailController extends BaseController {
public static function contact(){
$rules = [
'name' => 'required',
'email' => 'required|email',
'subject' => 'required|digits_between:1,6',
'message' => 'required'
];
$validator = Validator::make(Input::all(), $rules);
if (!$validator->fails()){
$data = ['subject' => Input::get('subject'),
'email' => Input::get('email'),
'content' => Input::get('message')];
Mail::send('emails.contact', $data, function($message){
$message->from(Input::get('email'), Input::get('name'));
$message->to('admin#email.com', 'Admin');
$message->subject(Lang::get('contact.option'.Input::get('subject')));
});
}
return Redirect::to('/');
}
}
There are 3 ways to achieve this:
You can change default language at runtime by doing this:
App::setLocale('fr');
NB: This is not suitable for your current need as it will only take effect on next page load.
You can set default language here app/config/app.php
'fallback_locale' => 'fr'
I took a deeper look at Illuminate\Translation\Translator:
get($key, array $replace = array(), $locale = null)
This means you can do this using Translator Facade:
Lang::get($key, array $replace = array(), $locale = null);
Example:
Lang::get('group.key',[],'fr');
NB: You folder structure should look like this
/app
/lang
/en
messages.php
/fr
messages.php
To get a language specific translation - different from the current locales without setting and unsetting the locales, just do
__('description_1', [], 'en')
Just set needed locale before calling Lang::get():
App::setLocale('es');
<?php
return [
'welcome' => 'welcome :name',
];
trans('welcome', [ 'name' => 'xyz' ], 'fr');
I would recommend something like this:
$savedLocale = App::getLocale();
App::setLocale($this->getUserMailingLanguage());
Mail::to($this->e_mail)->send($mailable);
App::setLocale($savedLocale);
I had exactly the same issue and found the desired answer.
This will provide you the desired result:
trans('welcome',array(),null,'fr');
This is working since Laravel vers. 5.2.