cakephp change language on fly - cakephp

My site is in 2 languages (english and italian)
My SiteMessagesController.php controller code:
public function index() {
$this->SiteMessage->locale = 'it';
$this->SiteMessage->recursive = 0;
$this->set('siteMessages', $this->paginate());
}
Above code shows all messages in italian language from database. If I comment the 1st line of code, then it will show messages in english.
If I go with this in whole site, I have to write $this->SiteMessage->locale = 'it'; line before $this->ModelName->find(); in each action of each controller.
Is there any way to set $locale to 'it' for each model?

If you're asking what I think you're asking, this will do:
Configure::write('Config.language', 'ita');
If you put this somewhere like your AppController::beforeFilter() it should work for the entire app, not individual models or queries. See book on I18n and L10n for more info.

put locale in AppModel.
eg: This one is for english
public $locale = 'en_us';

Related

How can i fetch dynamic data from database based on selected language.?

Hi i am working on a project in laravel 7.0, in back-end i have a table called Posts which contains 2 text language input one in french and the other is arabic added by the back-end application.
what i am trying to do is when the user uses the French Language i want the title_fr to be displayed on the view and same thing in Arabic language the title should be title_ar.
P.S data are stored in French and Arabic
I have tried the similar solution given in an other similar question but none of it worked in my case!
Any idea how i might get this to work ?
Thanks in advance.
You can do something similar to below. We have a model Post, this model has an attribute title. I also assume that you have an attribute that will return user's language from the User model.
class Post extends Model
{
public function getTitleAttribute(): string
{
return Auth::user()->language === 'fr' ? $this->title_fr : $this->title_ar;
}
}
FYI above is just a demo on what can be done. For a full blow solution I would recommend decorator pattern.
Also it might be worth considering using morph for things like that. You can have a service provider that will initiate the morph map for you post model relevant to the language that user has, I.e.
Class ModelProvider {
Protected $models = [
‘fr’ => [
‘post’ => App/Models/Fr/Post::class,
],
‘ar’ => [
‘post’ => App/Models/Ar/Post::class,
]
];
Public function boot() {
$language = Auth::user()->Settings->language;
Relation::morphMap($This->models[$language]);
}
}
Afterwards you just need to call to Relation::getMorphModel(‘post’) to grab Post class that will return correct language.
I.e. App/Models/Fr/Post can have a an attribute title:
Public function getTitleAttribute(): string {
Return $this->title_fr;
}
For example above you would also want to utilise interfaces to make sure that all models follow the same contract, something below would do the trick:
Interface I18nPostInterface {
Public function getTitleAttribute(): string
}
Also, depending on the database you use, to store titles (and other language data) in a JSON format in the database. MySQL 8 has an improve support for JSON data, but there are limitations with that.
So I was Able to fetch data from my database based on the Language selected by the user.
Like i said before I have a table called Posts and has columns id,title_fr and title_ar. I am using laravel Localization.
Inside my PostController in the index function i added this code:
public function index()
{
//
$post = Post::all();
$Frtitle = post::get()->pluck('title_fr');
$Artitle = post::get()->pluck('title_ar');
return view('post.index',compact('post','Frtitle','Artitle'));
}
if anyone has a better way then mine please let me know, i am sure
there is a better way.

October Database

I have this code
public function onRequest(){
$users = \Db::table('engegraph_forms_membros')->get();
foreach ($users as $part) {
echo $part->membro; // membro ITS NAME FROM ONE COLUMN IN MY DATABASE
}
}
My code
This works on page, but I want send this to a partial, in my database I have 3 columns and I want to show the values of column there.
Partial code
I have tried many ways but I don't understand well the docs, sorry for my English. If someone help me I would be grateful.
I am assuming you have this onRequest function on a component so write below code on it.
public function onRun(){
$this->page['users'] = $this->onRequest();
}
public function onRequest(){
return \Db::table('engegraph_forms_membros')->get();
}
now users variable will be available on your page and partial.

CakePHP 2.4 and Timehelper's timeAgoInWords locale

Recently I updated CakePHP from 2.3.9 to 2.4.4. As far as I remember (I can't test now) Timehelper::timeAgoInWords was working well in old CakePHP. But after this update I get locale problem. I change language to English, but time ago still comes in Turkish.
In core.php i already set default language to Turkish:
Configure::write('Config.language', 'tur');
Inside my view file I use this:
$d = "2012-05-02 20:17:30"
$myString = $this->Time->timeAgoInWords($d, array('end' => '+10 year'));
I get result in Turkish like this:
1 yıl, 8 ay, 4 hafta önce
I want result like this:
1 year, 8 months, 4 weeks ago
My session variables like this:
[Config] => Array
(
[userAgent] => 35db889a82essb4e57b540d52e8a766d
[time] => 1391121684
[countdown] => 10
[language] => eng
)
Although I set my language as English, result cames in Turkish. How can I debug/fix this ?
Edit:
I checked for Configure-language values. Results like this:
echo Configure::read( 'Config.language' );
result: tur
But
echo $this->Session->read('Config.language');
result: eng
As I noted in the top of my question, I already setted Configure::language inside my core.php file. Does core.php overrides my session value ?
Edit2:
And strange thing is, although Config.language looks like both "tur" and "eng", other parts inside my view file works well. For example this works well:
__("string")
Edit3:
Regarding to this page: http://book.cakephp.org/2.0/en/core-libraries/internationalization-and-localization.html
I added this:
class AppController extends Controller {
public function beforeFilter() {
if ($this->Session->check('Config.language')) {
Configure::write('Config.language', $this->Session->read('Config.language'));
}
}
}
After this change config language results like this:
echo Configure::read( 'Config.language' );
result: eng
echo $this->Session->read('Config.language');
result: eng
But I still see timeAgo result in Turkish..
Last week I migrated to new server, maybe some setting is missing for English or etc ? I can't understand why timeAgo doesn't work while __("string") works.
Edit4:
I even changed core.php like this:
Configure::write('Config.language', 'eng');
setlocale( LC_TIME, 'en_US.utf8', 'eng', 'en', 'en_US', 'en_UK' );
It seems like, in my configuration nothing changes timeAgoInWords's language. I override in every beforeFilter to change Config.language is to english, but still words are Turkish. Note that in my php.ini timezone is like this:
date.timezone = Europe/Istanbul
Edit5:
It seems like there is a problem in the translations. I checked for source code of timeago, here is a copy: https://github.com/cakephp/cakephp/blob/2.4.4/lib/Cake/Utility/CakeTime.php#L738
It seems like this method uses __d and __dn so I checked the results in my code. "az önce" means "just now" in Turkish.
I'm sure that Config.language is "eng". So:
echo __d('cake', 'just now', 'just now'); // results: "az önce"
echo __('just now'); // results: "just now"
echo __('az önce'); // results: "az önce"
$days=12;
echo __dn('cake', '%d day', '%d days', $days, $days); // results: "12 gün"
echo __('gün'); // results: "days"
To debug echo Configure::read( 'Config.language' ); right before your timeAgo call. If you find it's not "eng" then you are setting the language to English after timeAgo was already called.
IF that does not work then you may have to call setlocale as well
I use this for english dates:
setlocale( LC_TIME, 'en_US.utf8', 'eng', 'en', 'en_US', 'en_UK' );
And I guess this would the call for Turkish
setlocale(LC_TIME, 'tr_TR.UTF-8', 'tr_TR', 'tr', 'turkish');
PS: Looking at the history of the TimeHelper nothing was changed to affect the locale, but may a dependency was changed.
Normally I change current language like this:
$this->Session->write('Config.language', $lang);
I set default language like this in every request in core.php:
Configure::write('Config.language', 'tur');
Regarding to CakePHP documents I must add this code to my AppController:
class AppController extends Controller {
public function beforeFilter() {
if ($this->Session->check('Config.language')) {
Configure::write('Config.language', $this->Session->read('Config.language'));
}
}
}
After adding the code above to beforeFilter() of AppController, I refreshed /tmp/cache/persistent/ folder and everything works fine.
Edit:
This solution worked well for english but it didn't work for other languages.
Why ? As noted in this question cake looks for cake.po files inside your Locale folder.
For example if you want to see cake's messages in french, so you need to create this file:
/app/Locale/fra/LC_MESSAGES/cake.po
Where do CakePHP use cake.po records ?
For example: this method
You can create default po files like this: i18n shell tutorial
After shell's file creation, you can edit cake.po file for your language.
For some languages cake.po files are ready. For example: french file
You can find rest from there: https://github.com/cakephp/localized
For Russian language it`s necessary to set cake.po file encoding to utf-8, or you will see blank options instead of translated month names.
My solution is:
1. Place file cake.po in \app\Locale\rus\LC_MESSAGES directory and set
2. in AppController file
public function beforeFilter()
{
Configure::write('Config.language', 'rus');
}
Translation file for your language you can find in files of CakePHP Localized plugin https://github.com/cakephp/localized

grails: show list of elements from database in gsp

in my grails app I need to get some data from database and show it in a gsp page.
I know that I need to get data from controller, for example
List<Event> todayEvents = Event.findAllByStartTime(today)
gets all Event with date today
Now, how can I render it in a gsp page?How can I pass that list of Event objects to gsp?
Thanks a lot
You can learn many of the basic concepts using Grails scaffolding. Create a new project with a domain and issue command generate-all com.sample.MyDomain it will generate you a controller and a view.
To answer your question create a action in a controller like this:
class EventController {
//Helpful when controller actions are exposed as REST service.
static allowedMethods = [save: "POST", update: "POST", delete: "POST"]
def showEvents() {
List<Event> todayEvents = Event.findAllByStartTime(today)
[eventsList:todayEvents]
}
}
On your GSP you can loop through the list and print them as you wish
<g:each in="${eventsList}" var="p">
<li>${p}</li>
</g:each>
Good luck
I am not sure if this is really what you meant, because in that case I suggest you to read some more on the grails :), but anyway, for your case you can use render, redirect as well but here I am taking simplest way:
In your controller you have:
def getAllElements(){
List<Event> todayEvents = Event.findAllByStartTime(today)
[todayEvents :todayEvents ]
}
and then in the GSP(I assume you know about grails conventions, as if you don't specify view name, it will by default render gsp page with the same name as the function in the controller, inside views/):
<g:each in="${todayEvents}" var="eventInstance">
${eventInstance.<propertyName>}
</g:each>
something like this.

Computing table name from model name

In my CakePHP application, I have a model like this:
class Duck extends AppModel {
var $name = 'Duck';
function get_table_name() {
$tbl_name = //compute default table name for this model
}
}
I would like to write the function get_table_name() that outputs the default table name for the model. For the example above, it should output ducks.
EDIT:
Several people have pointed out the use of $this->table.
I did small testing and found out the following:
In the question as I have put above, $this->table indeed contains the table name.
However, actually, my code looked more like this:
class Duck extends Bird {
var $name = 'Duck';
function get_table_name(){
$tbl_name = //comput default table name for this model
}
}
class Bird extends AppModel {
}
In this case $this->table is empty string.
I went with this approach because I wanted to share some code between two of my models. Looks like this is not a good way to share code between models which need some common functionality.
You're looking for the Inflector class.
Inflector::tableize($this->name)
(tableize calls two Inflector methods to generate the table name: underscore() and pluralize())
Edit:
According to the source code, $this->table should contain the name of the table that CakePHP will use for the model, but in my experience this isn't always set. I'm not sure why.
To get the name of the table that the model is currently using, you can use: $this->table. If you don't manually change the model's table conventions, this may be the most useful in the case of CakePHP ever changing its conventions to use table names using something other than Inflector.
CakePHP's Inflector
function get_table_name() {
$tbl_name = Inflector::pluralize($this->name);
}
OR the tableize method
function get_table_name() {
$tbl_name = Inflector::tableize($this->name);
}
Edit
This also addresses the apparent "ghost" issue with $this->table in the Model.
Digging around in the __construct for Model I discovered two things:
Cake uses Inflector::tableize() to get the table name. This alone is enough to warrant using tableize over pluralize. You'll get consistent results.
$this->table is not set by the Model::__construct() unless $this->useTable === false AND $this->table === false.
It appears that if you know you haven't set $this->useTable to false you should be able to use this over $this->table. Admittedly though I only briefly scanned the source and I haven't really dug deep enough to say why $this->table isn't working sometimes.
To get the full table name for a model you have to take the table prefix into account.
$table = empty($this->table) ? Inflector::tableize($this->name) : $this->table;
$fullTableName = $this->tablePrefix . $table;
I used to use inflector to get the table name from model's name
$tableName = Inflector::pluralize(Inflector::underscore($model));
but this is not really universal, using useTable looks better, by default it will contain table's name by convention, and if you have a table that does not match the conventions, then you should manually specify it by useTable. So, in both cases the result will be correct
$this->User->useTable

Resources