CakePHP bootstrap array with parameters not translated - cakephp

I defined a configuration parameters in bootstrap, but they are not translated after in use.
$duedates = array(
'0'=> __('none'),
'1'=> __('8 days'),
'2'=> __('10 days'),
'3'=> __('15 days'),
'4'=> __('30 days'),
'5'=> __('45 days'),
'6'=> __('60 days'),
'7'=> __('90 days'),
'8'=> __('120 days'),
) ;
Configure::write('DUEDATES', $duedates);
They aren't trasnlated after using array
Configure::read('DUEDATES');
Where is the problem?

You can not define translatable strings in your bootstrap, as the language/locale is not yet set at that point. The bootstrap is processed before anything else, including the Config/core.php, which is where your language/locale settings should be. You should either:
Define the array at a later point, like in the beforeRender method of your AppController.
Move the language configuration to your bootstrap prior to defining the translatable strings.

Bootstrapping CakePHP
If you have any additional configuration needs, use CakePHP’s
bootstrap file, found in app/Config/bootstrap.php. This file is
executed just after CakePHP’s core bootstrapping.
This file is ideal for a number of common bootstrapping tasks:
Defining convenience functions.
Registering global constants.
Defining additional model, view, and controller paths.
Creating cache configurations.
Configuring inflections.
Loading configuration files.
Be careful to maintain the MVC software design pattern when you add
things to the bootstrap file: it might be tempting to place formatting
functions there in order to use them in your controllers.
Resist the urge. You’ll be glad you did later on down the line.
http://book.cakephp.org/2.0/en/development/configuration.html
It seems wrong to put localized strings into configuration. Their place seems to be in Views part of MVC.
CakePHP’s Configure class can be used to store and retrieve
application or runtime specific values. Be careful, this class allows
you to store anything in it, then use it in any other part of your
code: a sure temptation to break the MVC pattern CakePHP was designed
for. The main goal of Configure class is to keep centralized variables
that can be shared between many objects. Remember to try to live by
“convention over configuration” and you won’t end up breaking the MVC
structure we’ve set in place.

Related

Best configuration and parameters for ctags in a CakePHP project

What is the best configuration and parameters for ctags in a CakePHP project?
I want to be able to auto-complete ctp files, Components, Behaviours, Models and Helpers?
Check these github repositories, I have found then and they are so good for work with php and cakephp
https://github.com/amix/vimrc
https://github.com/ndreynolds/vim-cakephp
This solution requires 1 line in your .ctags file and two lines in your .vimrc file, so it's fairly minimal.
tl;dr
.ctags:
--langmap=php:+.ctp
.vimrc:
# Controller -> Component
map <leader>t yiw<cr>:tag /^<C-R>"<CR>
# View -> Helper
map <leader>h yiw<cr>:tag /^<C-R>"Helper<CR>
Add Views to your tags
This solution is mostly for jumping between files. I'll try and add auto-completion at a later date.
Add this to your ~/.ctags options file to include CakePHP views as PHP files:
--langmap=php:+.ctp
Then I'm assuming you've done ctags -R . at the root of your project (that's what I've done at least). This out of the box should pick up PHP syntax and class definitions.
Auto-completion (general)
I found the auto-completion (omni-completion from Ctrl+XCtrl+O) doesn't work very nicely with PHP, e.g. if I type $this-> and then try to auto-complete it doesn't find any tags.
The fix for this was to use install phpcomplete.vim. This will find methods within your class.
However that won't auto-complete connected models.
Models
By default ctags should work for all Controller -> Model jumping as the Model name is the same as the class name.
Behaviors
These again should be fine as you don't specify the name of the behavior you just have the method name which depending on how independent the name is it should get found - or at least it will be in the list of tags.
Components
There's no direct way of mapping these, I couldn't see a way of mapping them through the ctags --regex options. ctags recognises that they are classes but doesn't know the xxx -> xxxComponent mapping.
However there is one slight trick. You can do a tag search on the beginning of the class name (source)
:tag /^Email
will find
class EmailComponent
You can then map this in your .vimrc
map <leader>t yiw<cr>:tag /^<C-R>"<CR>
This copies the word that you've got the cursor over and then pastes it into the tag command and executes it. My leader is set to ,, so I can type ,t and it takes me to the corresponding component under the cursor.
Helpers
Ok, another slight hack in the .vimrc file:
map <leader>h yiw<cr>:tag /^<C-R>"Helper<CR>
Using ,h, this will jump you from $html->... to
class HtmlHelper extends AppHelper {
But it doesn't work for functions inside e.g. if your cursor is over script in $html->script, it will not take you to the HtmlHelper script method. So it's a work in progress.

Dynamic locale name in multi-language site

I am developing an application in cakephp 2.3.4, Which is multi-language.
Admin can add any number of new languages.
My question is, When admin decides to add a new language, how resulting locale name should be defined.
Can a locale name be any arbitrary name, given by admin or it should be a dropdown containg all languages code according to language.
Unfortunately, your question is a bit 'vague', i.e., will administrators be able to add GNU-locale files (*.po), or are you talking about adding translations inside the database.
In any case, CakePHP uses locales according to the ISO 639-3 standard see here and here for more information. A complete list of those locales can be found inside the I10n class.
Since you probably also want to switch the locale of PHP itself when switching locales, so that, for example, date, money and time-formats will follow the right format for the locale, it's best to stick with those locales and not 'invent' your own locales.
See setlocale(). Be aware though, that PHP may use slightly different locale-codes than CakePHP uses. And it will depend on what locales are installed on your server.
To get a list of locales installed on your server, use locale -a on the command line. See this page for more information: https://wiki.archlinux.org/index.php/Locale
Which techniques to use for localization
A quick summary of techniques to use;
Short messages (interface/UI)
In general, locale files are used for short pieces of text. Locale-files are therefore mostly used for fixed strings,
for example, strings that are used in the interface (like 'are you sure you want to delete this file?' => 'weet u zeker dat u dit bestand wilt verwijderen?).
Longer (fixed) text
For longer pieces of text in your application, that are not part of the 'content' (not the blog-post, but for example a fixed page with a disclaimer),
it's best to use separate views for translated content, for example;
app/Views/MyController/disclaimer_eng.ctp
app/Views/MyController/disclaimer_deu.ctp
app/Views/MyController/disclaimer_fre.ctp
Content
For the content of your website (the part of your website that is managed by the 'user' of the website),
put translations inside the database. This data may be updated frequently and all translations should be updated as well.
How to implement this, is really up to you and depends on your situation. CakePHP offers a Translate behavior that you can use (http://book.cakephp.org/2.0/en/core-libraries/behaviors/translate.html), but in most of my situations that behavior didn't really fit our needs (IMO it is not very efficient, because it stores translations per-field, per-model).

ExtJS MVC, dynamic loading and i18n

I would like to translate my ExtJS application in different languages. My issue is that I'm using ExtJS MVC framework, and most of my JS files are downloaded dynamically by the framework itself.
The ideal solution (that I thought of) would be to have an extra option in the Ext.Loader (or in my Ext.app.Application) that would define the language to use, and depending on this to automatically download such file as "a.MyClass.fr.js" after loading my "a.MyClass.js" (which would contain an Ext.apply, overriding my string resources). That's probably not available in the ExtJS framework at the moment.
The alternative solution I can see, is to perform a trick on the server-side. First, a cookie would be created on the client, to set to the language. On the server-side, I could catch all the requests to JS files, then if a cookie is set (='fr' for example), I'd combine the requested JS file (MyClass.js) with its i18n's friend (MyClass.fr.js) dynamically on the server and return the result. That would work, but it's really tricky because it implies other things (caching...).
Maybe the best way is to implement the first behavior I described in the ExtJS framework myself...
What do you think? I'm looking for a really clean and neat way of doing it! Thanks :)
I recently struggled with the same problem.
Finding a clean way to do this was quite a challenge - most alternatives were either..
1) Duplicate your code base per locale (WTH)
2) Download localized files overriding each of your components (Maintenance hell? What about the poor translators?)
3) Use/generate a static file containing translations and refer to it (All languages are downloaded? Extra build step to generate it? How do you keep them in synch?)
I tried to get the best of all worlds and ended up with a utility class responsible for:
1) Loading the ExtJS translation files (which basically apply overrides to extjs base components)
2) Loading a locale specific property resourcebundle (specifying which locale to load) from the server.
3) Prototyping String with a translate() method which queries the loaded store (containing the message bundle from the server) and returns the translation based on the value of the string.
This is the gist of things:
Bundle & prototyping:
localeStore.load({
callback : function(records, operation, success) {
// Define translation function (NB! Must be defined before any components which want to use it.)
function translate() {
var record = localeStore.getById(this.valueOf()) ;
if(record === null) {
alert('Missing translation for: ' + this.valueOf()); // Key is not found in the corresponding messages_<locale>.properties file.
return this.valueOf(); // Return key name as placeholder
} else {
var value = record.get('value');
}
return value;
}
String.prototype.translate = translate;
callback.call(); // call back to caller(app.js / Ext.Application), loading rest of application
}
});
As an example from a view:
this.copyButton = Ext.create('Ext.button.Button', {
disabled: true,
text: 'DOCUMENT_LIBRARY_MENU_COPYTO_BUTTON'.translate(),
action: 'openCopyDialog'
});
Bundle on the server (mesages_en.properties):
DOCUMENT_LIBRARY_MENU_COPYTO_BUTTON=Copy file
etc..
Pros:
No-fuss code, 'Your_key'.translate() makes it easy to read and aware that this is a localized string
None/little maintenance overhead (Keeping an override file for each locale? Jesus..)
You only load the locale you need - not the whole shabang.
If you really want to, you could even have your own translation for the ExtJS locale files in the same bundle.
You could write unit tests to ensure that all bundles contain the same keys, thus avoiding orphaned translations later
Cons:
Synchronous - the store must be loaded before your main app starts. I solved this by adding a callback from the utility class which was called once all texts were loaded.
No real-time population of texts.. though I didn't want to make my users overload the server either :P
So far my approach has worked out pretty well for my requirements.
Site load isn't noticeably slower and the bundles (containing ~200 keys/values per bundle) measure out at ~10kb during load.
There is currently no solution so I decided to create my own hack/addon on the Ext.Loader. I uploaded the code on GitHub: https://github.com/TigrouMeow/extjs-locale-loader. It's exactly what I needed and I really hope it will help others as well!
You should first complete your development phase and build your project or use ext-all.js file to I18s translate your UI
see: http://docs.sencha.com/ext-js/4-0/#!/example/locale/multi-lang.html
The appropriate language modifier script (/ext/local/ext-lang-xxx.js) needs to be loaded after ext is loaded (including dynamically loaded classes). In the example above, I would have probably used Ext.Loader.loadScriptFile but they eval a downloaded one directly. The only other thing is that your classes need to be built in different languages or you just use variables and reference the lang-specific variable file.
you could also use a variable in the Loader paths:
var lang='fr';
Loader
{
paths:
{
'Ext': '.',
'My': './src/my_own_folder'+'/'+lang
}

CakePHP routing syntax

How do I do a simple route in CakePHP?
I need that each and every URL will be routed by swapping the action and the controller.
I just couldn't understand the placeholders syntax.
Example:
/files/read/3
to
/read/files/3
-- supplemental --
In my application I use aliases for the controllers.
and I want to route every url that have a certain keyword, as an action, to a certain controller.
I also want to provide the original controller name as a parameter.
Here is a 1:1 example:
There are to alises: fruits and streets.
The keyword that I want to catch in the action is find.
The new controller name is finder.
The following calls match my condition:
/fruits/find/apple/red and /streets/find/longer
The router should catch these urls and convert them, to:
/finder/fruits/apple/red(or supply the parameters in other way, I don't mind) and /finder/streets/longer
How should it be done?
Here is the line of code that you need to put in /app/config/routes.php:
Router::connect('/:action/:controller/*', array('controller' => ':controller', 'action' => ':action'));
Know more: As you can see from the CakePHP book, there are some 'reserved' patterns for routing configuration. An example would be what I used in the line above: :action and :controller. These patterns allow you to tweak routes extensively.
Beware: changing the order of controller and actions in urls might have unintended consequences in the functionality of other CakePHP features. I haven't tested thoroughly, but this is just a general warning.
Beware: Also, I noticed that you put in your example: /files/read/3. Maybe this was just some dummy example, but if you indeed plan to have an MVC named as 'file', be advised that it will conflict will CakePHP core classes (e.g. File model will conflict with File class).
Anyway, hope this answer helps you well. And I really like how the change of controller and action names make the url more readable. :D

Dealing with Alias URLs in CakePHP

I am rewriting our company website in cakephp, and need to find a way to do the following:
A user enters our site by using one
of the promotional alias URLS that
has been pregenerated for a specific
media advert ( magazine, web
promotion etc )
The URL is checked against a
database of alias URLs, and if an
alias exists, then a specific
tracking code is written into the
session.
I have considered several options, none of which seem suitable for this purpose. They are:
Putting the lookup script in the
beforeFilter() in appcontroller, so
that its included in every
controller. (Writes a session value
so it only perfoms once.)
This option only works for existing contollers, and gives the
Cake 'missing controller' error if a
URL doesn't exist.
Specific routes for each alias in
Routes.php - Works but there are
potentially hundreds of alias urls
added/removed regularly via admin
interface.
Route all site URLs to their own
actions, and having an 'everything
else' rule, for the alias URLs that
maps to my lookup script. - Messy
and I lose the built in Cake
routing.
Custom 404. - I don't want to
return 404's for these urls, as I
feel its bad practice unless they
really don't map to anything.
I really could do with a place in the application flow where I can put this lookup/tracking script, and I'm fairly new to cake so I'm stumped.
EDIT: Also, I know that a subfolder called say 'promo' would easily do this, but I have a lot of legacy URLS from our old site, that need handling too.
Note: I'm making an assumption that your promo URLs are in the form of "domain.com/advert-259" or something like that (i.e. no "domain.com/adverts/advert-259'). That would be just too simple :)
Hopefully, you can use the routing with some regex. Add this to your /config/routes.php and let me know if a different regex will help :)
$controllers = Configure::listObjects('controller');
foreach ($controllers as &$value)
{
$value = Inflector::underscore($value);
}
Router::connect('/:promo', array('controller' => 'promos', 'action' => 'process'), array('promo' => '(?!('.implode('|', $controllers).')\W+)[a-zA-Z\-_]+/?$'));
Now you can handle all your promo codes in PromosController::process().
Basically, it checks for a promo code in url, excluding those in the $controllers array (i.e. your regular routes won't be messed up).
Later on you might want to consider caching the value of Configure::listObjects() depending on the speed of your app and your requirements.
A very interesting question. I think I would use item #3. It's not really that messy -- after all, this typically is handled by the pages controller in my stuff. That's how I'd handle it - hardcode your routes to your controllers in routes.php, then have a matchall route that will work for your promo codes. This allows you to keep legacy URLs, as well as use a lot of the standard cake stuff (you probably will just have to explicitly state each of your controllers routes, not such a chore...) Additionally, it will let you do some cool stuff with 404 errors -- you can put some logic in there to try and figure out where they were trying to go, so you can superpower your 404's.

Resources