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
Related
I have this form in CakePHP:
echo $form->input('name', array('label' => $j['contact_name']));
echo $form->input('email', array('class' => 'disabled', 'label' => $j['contact_mail']));
echo $form->end(__('Submit', true));
I have two different languages, so I want to change name into name, but when I do that it doesn't work. Anybody help me how will this work in CakePHP.
Thanks!
You'll have to use the 'Localization' features of CakePHP
http://book.cakephp.org/2.0/en/core-libraries/internationalization-and-localization.html
Basically, any string that should be translated in the current language, should be echoed via the __() method, for example echo __('hello')
The string 'hello' in this example is the string to be localised (translated). CakePHP uses GNU locale files to define your translations. In these files are 'pairs' of strings, called msgid (the string/message to be translated) and msgstr (the translated string). Each language ('locale') has its own translation file, located in:
app/Locale/[locale]/LC_MESSAGES/default.po
For example, to have a 'Dutch' translation (locale 'nld'), this file:
app/Locale/nld/LC_MESSAGES/default.po
Should be created, containing:
msgid "hello"
msgstr "hallo"
Now, by switching the locale to 'nld' (for example in the beforeFilter() of your AppController;
Configure::write('Config.language', 'nld');
The 'nld' locale will be used and this line;
echo _('hello');
Will output:
hallo
In your case, setting the label would be something like this;
echo $this->Form->input('name', array('label' => __('hello')));
important
older versions (before CakePHP 2.x) 'echoed' the translated string in stead of returning the translated string. To return the translated string in CakePHP 1.x, you need to pass 'true' as second parameter; echo __('hello', true);
Strings in .po files are case sensitive, e.g. Hello !== hello
Locale files are meant for 'short', fixed text in your application, not to translate big pieces of text or 'dynamic' text, entered by the user. although it is possible to use it for these situations, it is not designed for this.
There are several other changes between CakePHP 2.x and 1.x, so in all cases, make yourself familiar with the whole concept by reading the manual.
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';
I am having trouble with my cakePHP and wondering if anyone else has experienced this. I am trying to setup a User object. I create the Model:
class User extends AppModel
{
}
I create the controller:
class UsersController extends AppController
{
function view($id = null) {
$this->User->id = $id;
$this->set('users', $this->User->read());
}
}
and I go to the view page. However, I am not getting what the cake documentation says I should be getting. I am getting:
Array
(
[0] => Array
(
[id] => 3
[FirstName] => 1
[LastName] => 1
)
)
when what I am expecting to see is
Array
(
[User] => Array
(
[id] => 3
[FirstName] => 1
[LastName] => 1
)
)
Also when I do a $this->User->find('all'); I get back an array like so:
Array
(
[0] => Array ([0] => Array (/*stuff here*/))
[1] => Array ([0] => Array (/*stuff here*/))
[2] => Array ([0] => Array (/*stuff here*/))
)
I have tried changing the name to Myuser (including the database table, controller, model, etc) and still have the same results, so I don't think it's related to a reserved keyword.
Has anyone run into this or, more importantly, does anyone have a clue how I might fix it? Thanks.
EDIT:
I am using cake version 2.0.6. I am using a MySQL 5.0.92 database. I just have tried setting the name variable and it did not change my results.
After an ENTIRE DAY of troubleshooting, I finally was able to solve it.
The cause is definitely an outdated pdo_mysql.so library. This is located in /usr/local/lib/php/extensions/(latest directory)/pdo_mysql.so
The table name being returned in getColumnMeta was only added in a certain version due to this function request:
https://bugs.php.net/41416/
Now, the problem is, in some web hosts, PHP needs to be compiled with Easy Apache. Mine had to go through that as well just in order to enable PDO (it was initially disabled). But the problem is, for some reason, Easy Apache is downloading some obsolete source code everytime it runs. Running yum or installing any RPMs don't help either.
So here is what I did:
- I downloaded the latest PHP sources from the PHP site, extracted the tarball
- I ran Easy Apache, did a recompilation, and very quickly went to the console to watch it redownload the outdated PHP sources
- When the PHP sources have reappeared, I very quickly replaced the entire ext/pdo_mysql directory with the latest sources
- Easy Apache will compile httpd first, so you have some time to do the above step
- After the build is done, reboot.
- To check if your version of pdo_mysql.so supports the table name, execute this command:
strings -f pdo_mysql.so | grep ': table'
- There should be an entry there. The old version doesn't.
- By the way, I noticed that there are more copied of the pdo_mysql.so in /usr/lib/php/modules and /usr/lib/php/extensions, but it seems that the one in /usr/local is the one that is active. Nevertheless, I update all copies manually
NOTE: if you just try to update the pdo_mysql.so file, it will not work. You will get a segmentation fault, and the pages will render nothing. You need to recompile PHP using the above steps.
I hope this will help other people who will come across this bug.
Be sure your table is named users and include the association explicitly
class User extends AppModel {
public $name = 'User';
public $useTable = 'users';
...
You need to set the $uses variable to associate the User model with the controller if you are using any additional models. Adding it explicitly even if there's just one will not hurt either...
for example
class UsersController extends AppController {
//Controller Name
public $name = 'Users';
//DB Config for desired connection
public $useDbConfig = 'test';
// Array of associated models
public $uses = array('Store','User');
//Array of Helpers used by Controller Views
public $helpers = array('Html', 'Form');
...
Also, check to be sure there are no edits in AppModel or AppController which may be accidentally contributing to the interactions here... You may also consider dumping the value of the $uses to see what's there.
Finally found out that the reason for it has to do with a function called PDOStatement::getColumnMeta. This gets called on the queries that cakePHP runs is used by the framework to get the column name, column type, and table name. However, for whatever reason, on the webhost I currently have, this function does not return the table name so cakePHP defaults to creating the array with a 0 index rather than a table name index.
$column = $results->getColumnMeta($index);
if (!empty($column['table']) && strpos($column['name'], $this->virtualFieldSeparator) === false) {
$this->map[$index++] = array($column['table'], $column['name'], $type);
} else {
$this->map[$index++] = array(0, $column['name'], $type);
}
still not sure how to fix it yet, but this is definitely why it is happening.
Yes, you are right. beastmaster
The reason why is that u using old version of PDO driver which has been been deprecated. the PDOStatement::getColumnMeta does not show [table]=name in old version
So solution here download new version of PHP which has build-in PDO. DO NOT INSTALL PDO VIA PECL coz u getting old version of PDO extension. and using
<?php phpinfo ?>
to check if it is installed properly. so u can use native PDO driver coming with PHP rather than use extension PDO driver.
By the way, Thank you for point out the problem.
I have just faced the problem. The cause was not an outdated pdo_mysql.so library.
If you use cakephp 2.3.x and make sure to use PHP 5.2.8 or greater, you should check whether the pdo_mysql extension is enabled or disabled.
You can echo phpinfo() to check it.
Note: the pdo_mysql extension is only enabled if you see "PDO Driver for MySQL enabled", otherwise it is disabled.
How can I change the extension for CakePHP Views from .ctp to .php
I have seen there is this line in /cake/libs/view.php var $ext = '.ctp'; that sets the extension but how can I do it from my /app/ folder so it doesn't effect Cake core files.
Thanks
You can set the extension in your AppController with
public $ext = '.yourext';
This is is reply to Cameron's comment regarding the issue of using multiple extensions in light of the fact cakephp does not allow you to specify multiple extensions.
I am using Mustache for a single site that uses merb, rails2, rails3 and cakephp for different sections of the site. The cake site "receives" mustache files for common layout elements but these templates have a '.mustache' file extension which my cake site will not recognize. My workaround is basically what dhofstet suggests just framed in the context of your specific usecase. In short, create a wrapper that might look something like this:
<?
$tmp = $this->ext;
$this->ext = '.mustache';
?>
<?= $m->render($this->renderElement('moznav/advanced_header'), array('foo' => $bar)) ?><br />
<? $this->ext = $tmp; ?>
When flow returns to the caller, you keep on using your native file extension.
How can I change the extension for CakePHP Views from .ctp to .php
I have seen there is this line in /cake/libs/view.php var $ext =
'.ctp'; that sets the extension but how can I do it from my /app/
folder so it doesn't effect Cake core files.
example:
you have view posts/add.ctp
now you rename add.ctp into add.php
and then you run .../posts/add the message error show:
Error: The view for PostsController::add() was not found.
to your app can understand extention .php, you add line public $ext = '.php' in PostsController.php
now, you run again ..posts/add => okie, cakephp understand extention .php
Notice: if you use atrribute $ext = '.php' but file view named .ctp, cakephp extention .ctp will use by default
I found this post because I had the same problem. This is not mentioned in the Predominant TwigView plugin documentation on Github. I'm tired of those documentations that explains only half of things and with which we have to guess the second half. This is a big waste of time that slows down projects pointlessly.
I am confused :)
I'm using the p18n component in cakephp found here:
http://www.palivoda.eu/2008/04/i18n-in-cakephp-12-database-content-translation-part-2/
This component requires me to set in core.php the following constant:
define("DEFAULT_LANGUAGE", 'eng')
However when this is set I cannot change the language using:
Configure::write('Config.language', 'eng');
At the moment, into my knowledge, the only way to change the locale of my static content is the use of the Configure::write. But for the dynamic content to change through the use of the p28n component I must have the DEFINE_LANGUAGE constant set to a value.
This is all very confusing. Any help will be much appreciated.
I'm not familiar with particular component, but I've done this "manually" by setting the same constant in my app/config/bootstrap.php file and then setting the "actual" language to be used in my AppController (copied from the core code to app/app_controller.php). The appropriate snippets of that controller look like this:
uses ( 'L10n' );
class AppController extends Controller {
public function beforeFilter() {
$this->_setLanguage();
/**
* Set the default "domain" for translations. The domain is the
* same as the po file name in a given locale directory. e.g.
* __d ( 'homepage', 'message_id' ) would look for the
* message_id key in homepage.po. Using the __() convenience
* function will always look in default.po.
*/
$this->set ( 'domain', 'default' );
}
private function _setLanguage() {
$this->L10n = new L10n();
# Auto-detect the request language settings
$this->L10n->get();
}
}
Pretty vanilla stuff, but it works great. And breaking out the _setLanguage() method allows for the use of different methodologies to determine locale (e.g subdomain like fr.mydomain.com).