CakePHP plugin localization in different files - cakephp

I've made ContentManager plugin for my cakephp (3.2) apps. It has base translation file in /plugins/ContentManager/src/Locale/ru/content_manager.po.
Now I want to add some additions translations on application level. So I need some additional po file for my plugin. If I put one more content_manager.po file in app\src\Locale\ru folder, it overrides base file.
Is it possible to add file like content_manager.0.po, content_manager.base.po or something, and make whem work together? Anyway I need to extend plugin transalations somehow.
base file contains strings like these
msgid "tab_MenuItems"
msgid "content.type.News"
msgid "users.role.admin"
and so on.
Additional file contains application-specific strings like:
msgid "content.type.Products"
msgid "content.type.Orders"
msgid "users.role.manager"
plugin itself uses translations like (example, smarty) this:
{foreach $registered_types as $ct}
<li>{__d("content_manager", "content.type.$ct")}</li>
{/foreach}

You can add a default.po file in your apps ru locale folder, this file will by default be used by the so called "fallback loader", which is going to be used in case the requested message ID cannot be found in the primary domain, ie in content_manager.po.
In case you need more control, you can always build custom loaders/packages, like for example:
use Cake\I18n\I18n;
use Cake\I18n\MessagesFileLoader;
I18n::config('content_manager', function ($name, $locale) {
$fileLoader = new MessagesFileLoader('content_manager', $locale, 'po');
/* #var $package \Aura\Intl\Package */
$package = $fileLoader();
$package->setFallback('content_manager.base');
return $package;
});
This would create a loader that internally pre-loads the default content_manager domain messages, and set the fallback loader domain to content_manager.base, so that it would try to load messages from your content_manager.base.po file in case there's no translation present in the default domain.
And don't forget to clear the cache (tmp/cache/persistent) after adding/modifying translations/loaders.
See also
Cookbook > Internationalization & Localization > Creating Generic Translators
API > \Cake\I18n\I18n::config()
API > \Cake\I18n\MessagesFileLoader

Related

Cached translations in CakePHP 3.7.4

I have taken over a project on cakephp.
The problem is that I can not change translation texts.
Under src/Locale I have:
en_EN
default.mo
default.po
no_NO
default.mo
default.po
cake.pot
default.pot
In controller
public function view($id)
{
$order = $this->Order->get($id);
$this->set(compact('order'))
}
In view I have a form where is translated text by default
<?= $this->Form->control('email_message', [
'type' => 'textarea',
'rows' => 15,
'help' => sprintf('Email will be sent to %s', h($order->contact_email)),
'default' => __('pickup_mailtext')
]) ?>
No I have in
en_EN
default.po
msgid "pickup_mailtext"
msgstr "This is the old pickup mailtext"
if I change it to
msgid "pickup_mailtext"
msgstr "This is the NEW pickup mailtext"
Nothing changes. I have deleted everything in persistent directory.
Also in Config/app.php default language is set to no_NO, but as I mentioned before this string is under en_EN
under
no_NO
default.po
There is:
msgid "pickup_mailtext"
msgstr ""
I have also noticed, tad this string is in
en_EN
default.mo
but if I try to modify it I get Internal server error.
So my question is:
1. How to get this translation working? Why this string is not changing?
2. If the default language is set to no_NO, then why the translations is in en_EN and why it is getting translated instead of being empty?
3. How to clear those .mo files?
Thanks
.mo files are the compiled binary versions of the respective .po files, you can't just modify them with a text editor, you need to recompile the .po files instead, using a program like msgfmt, or one with a GUI like Poedit.
CakePHP will by default prefer .mo files over .po files (the former are usually faster to parse), ie if a .mo file exists it will be used instead of a possible .po file with the same name, so if you change only the .po file, nothing will happen as that file is not being used.
If changing the default locale in config/app.php has no effect, then the locale might get changed somewhere else in your app. Check \Cake\I18n\I18n::getLocale() in your view template to figure what locale is actually being used at that point, and set a breakpoint in \Cake\I18n\I18n::setLocale() (vendor/cakephp/cakephp/src/I18n/I18n.php) or log a stacktrace to figure from where in the code the locale is being set.

Symfony CMF RoutingBundle - PHPCR Route Document - Multiple Parameters

Tried to find a solution, but I got always stuck a the docs or at answers include other bundles. In the documentation of the dynamic router you can find the hint:
"Of course you can also have several parameters, as with normal Symfony routes. The semantics and rules for patterns, defaults and requirements are exactly the same as in core routes."
Thats it.
...
/foo/{id}/bar
I tried (seems not) everything to get it done.
Same for all tries:
I tried it to apply a variable pattern and a child route.
use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route as PhpcrRoute;
$dm = $this->get('cmf_routing.route_provider');
$route = new PhpcrRoute();
$route->setPosition( $dm->find( null, '/cms/routes' ), 'foo' );
$route->setVariablePattern('/{id}');
$dm->persist( $route );
$child = new PhpcrRoute();
$child->setPosition( $route, 'bar' );
$dm->persist( $child );
$dm->flush();
With or without default value and requirement only '/foo/bar' and '/foo/*' return matches, but '/foo/1/bar' prompts me with a 'No route found for "GET /foo/1/bar"'.
...
Just now I nearly got it done.
use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route as PhpcrRoute;
$dm = $this->get('cmf_routing.route_provider');
$route = new PhpcrRoute();
$route->setPosition( $dm->find( null, '/cms/routes' ), 'example_route' );
$dm->persist( $route );
$route->setPrefix( '/cms/routes/example_route' );
$route->setPath( '/foo/{id}/bar' );
$dm->flush();
If prefix is '/cms/routes' and name is 'foo' everything works fine. But now that I got this far, assigning a speaking name would round it up.
Thanks in advice!
You got quite close to the solution, actually!
When using PHPCR-ODM, the route document id is its path in the repository. PHPCR stores all content in a tree, so every document needs to be in a specific place in the tree. We then use the prefix to get a URL to match. If the prefix is configured as /cms/routes and the request is for /foo, the router looks in /cms/routes/foo. To allow parameters, you can use setVariablePattern as you correctly assumed. For the use case of /foo/{id}/bar, you need to do setVariablePattern('/{id}/bar'). You could also have setVariablePattern('/{context}/{id}') (this is what the doc paragraph you quoted meant - i will look into adding an example there as its indeed not helpful to say "you can do this" but not explain how to).
Calling setPath is not recommended as its just less explicit - but as you noticed, it would get the job done. See the phpdoc and implementation of Model\Route::setPattern:
/**
* It is recommended to use setVariablePattern to just set the part after
* the static part. If you use this method, it will ensure that the
* static part is not changed and only change the variable part.
*
* When using PHPCR-ODM, make sure to persist the route before calling this
* to have the id field initialized.
*/
public function setPath($pattern)
{
$len = strlen($this->getStaticPrefix());
if (strncmp($this->getStaticPrefix(), $pattern, $len)) {
throw new \InvalidArgumentException('You can not set a pattern for the route that does not start with its current static prefix. First update the static prefix or directly use setVariablePattern.');
}
return $this->setVariablePattern(substr($pattern, $len));
}
About explicit names: The repository path is also the name of the route, in the example /cms/routes/foo. But it is not a good idea to use a route name of a dynamic route in your code, as those routes are supposed to be editable (and deletable) by an admin. If you have a route that exists for sure and is at a specific path, use the configured symfony routes (the routing.yml file). If its dynamic routes, have a look at the CMF Resource Bundle. It allows to define a role for a document and a way to look up documents by role. If you have a route with a specific role that you want to link to from your controller / template, this is the way to go. If you have a content document that is linked with a route document and have that content document available, your third and best option is to generate the URL from the content document. The CMF dynamic router can do that, just use the content object where you normally specify the route name.

Save file on disk with name based on title of object

If in Yii 1.1.x there is some extension, to create valid file system(linux) name from object title with unique name, like a slug, but with unique name in given directory ?
I mean I want to save file on disk with name based on title of object.
Thanks!
Actually I would like a bit more :
1) In title of object all illigel chars(for Linux/windows OS) and space must be converted to '-'
2) if there is such file add valid counter for it , like "_45"
Maybe that not yii extension, but some php function.
The simplest way - you can add object id to prefix of file. Then your file names always be uniqueness. For example:
1-title-first
2-title-first
3-title-second
you can use php own uniqueid() to generate unique ids!
$title = uniqid('wp_'); // have wp_ prefixed for title

Where to put Symfony2 custom parameters I need?

I need to have some configuration for my bundle in Symfony2
Where is the best place to put them?
and how can I retrieve them from there?
I used my Default DB parameters in PARAMETERS.INI But I need Extra ones that I can retrieve them personally in code.
One should keep his parameters inside the bundles, for instance
src/Company/SomeBundle/Resources/config/parameters.yml
To define any extra parameters you need, define them in your config.yml file. Something like:
# app/config/config.yml
parameters:
my_mailer.class: Acme\HelloBundle\Mailer
my_mailer.transport: sendmail
Then you can retrieve them anywhere that the service container is available, for example inside a controller, just like you retrieve any other service like doctrine or swiftmailer. For example, in a controller, do
$transport = $this->get('my_mailer.transport');
If you want, you can define these parameters in paramters.ini, you will get the same result.
See the How to expose a Semantic Configuration for a Bundle cookbook entry. One of the advantages of this approach is that you can validate the configuration.
use different parts in parameters.ini file. You could have a prod1 environment using parameters prefixed with prod1 and a prod2 with the same:
parameters.ini:
[parameters]
prod1_database_driver = pdo_mysql
prod1_database_host = 127.0.0.1
# ...
prod2_database_driver = pdo_mysql
prod2_database_host = localhost
They both use the prod.yml configuration but overwrite the stuff you want to read from the parameters.ini:
config_prod1.yml:
imports:
- { resource: config_prod.yml }
// .. overwrite stuff here

the best way to make codeigniter website multi-language. calling from lang arrays depends on lang session?

I'm researching hours and hours, but I could not find any clear, efficient way to make it :/
I have a codeigniter base website in English and I have to add a Polish language now. What is the best way to make my site in 2 language depending visitor selection?
is there any way to create array files for each language and call them in view files depends on Session from lang selection? I don't wanna use database.
Appreciate helps! I'm running out of deadline :/ thanks!!
Have you seen CodeIgniter's Language library?
The Language Class provides functions
to retrieve language files and lines
of text for purposes of internationalization.
In your CodeIgniter system folder you'll
find one called language containing sets
of language files. You can create your
own language files as needed in order
to display error and other messages in
other languages.
Language files are typically stored in
your system/language directory. Alternately
you can create a folder called language
inside your application folder and store
them there. CodeIgniter will look first
in your application/language directory.
If the directory does not exist or the
specified language is not located there
CI will instead look in your global
system/language folder.
In your case...
you need to create a polish_lang.php and english_lang.php inside application/language/polish
then create your keys inside that file (e.g. $lang['hello'] = "Witaj";
then load it in your controller like $this->lang->load('polish_lang', 'polish');
then fetch the line like $this->lang->line('hello'); Just store the return value of this function in a variable so you can use it in your view.
Repeat the steps for the english language and all other languages you need.
Also to add the language to the session, I would define some constants for each language, then make sure you have the session library autoloaded in config/autoload.php, or you load it whenever you need it. Add the users desired language to the session:
$this->session->set_userdata('language', ENGLISH);
Then you can grab it anytime like this:
$language = $this->session->userdata('language');
In the controller add following lines when you make the cunstructor
i.e, after
parent::Controller();
add below lines
$this->load->helper('lang_translate');
$this->lang->load('nl_site', 'nl'); // ('filename', 'directory')
create helper file lang_translate_helper.php with following function and put it in directory system\application\helpers
function label($label, $obj)
{
$return = $obj->lang->line($label);
if($return)
echo $return;
else
echo $label;
}
for each of the language, create a directory with language abbrevation like en, nl, fr, etc., under
system\application\languages
create language file in above (respective) directory which will contain $lang array holding pairs label=>language_value as given below
nl_site_lang.php
$lang['welcome'] = 'Welkom';
$lang['hello word'] = 'worde Witaj';
en_site_lang.php
$lang['welcome'] = 'Welcome';
$lang['hello word'] = 'Hello Word';
you can store multiple files for same language with differently as per the requirement
e.g, if you want separate language file for managing backend (administrator section) you can use it in controller as $this->lang->load('nl_admin', 'nl');
nl_admin_lang.php
$lang['welcome'] = 'Welkom';
$lang['hello word'] = 'worde Witaj';
and finally
to print the label in desired language, access labels as below in view
label('welcome', $this);
OR
label('hello word', $this);
note the space in hello & word you can use it like this way as well :)
whene there is no lable defined in the language file, it will simply print it what you passed to the function label.
I second Randell's answer.
However, one could always integrate a GeoIP such as http://www.maxmind.com/app/php
or http://www.ipinfodb.com/. Then you can save the results with the codeigniter session class.
If you want to use the ipinfodb.com api You can add the ip2locationlite.class.php file to your codeigniter application library folder and then create a model function to do whatever geoip logic you need for your application, such as:
function geolocate()
{
$ipinfodb = new ipinfodb;
$ipinfodb->setKey('API KEY');
//Get errors and locations
$locations = $ipinfodb->getGeoLocation($this->input->ip_address());
$errors = $ipinfodb->getError();
//Set geolocation cookie
if(empty($errors))
{
foreach ($locations as $field => $val):
if($field === 'CountryCode')
{
$place = $val;
}
endforeach;
}
return $place;
}
For easier use CI have updated this so you can just use
$this->load->helper('language');
and to translate text
lang('language line');
and if you want to warp it inside label then use optional parameter
lang('language line', 'element id');
This will output
// becomes <label for="form_item_id">language_key</label>
For good reading
http://ellislab.com/codeigniter/user-guide/helpers/language_helper.html
I've used Wiredesignz's MY_Language class with great success.
I've just published it on github, as I can't seem to find a trace of it anywhere.
https://github.com/meigwilym/CI_Language
My only changes are to rename the class to CI_Lang, in accordance with the new v2 changes.
When managing the actual files, things can get out of sync pretty easily unless you're really vigilant. So we've launched a (beta) free service called String which allows you to keep track of your language files easily, and collaborate with translators.
You can either import existing language files (in PHP array, PHP Define, ini, po or .strings formats) or create your own sections from scratch and add content directly through the system.
String is totally free so please check it out and tell us what you think.
It's actually built on Codeigniter too! Check out the beta at http://mygengo.com/string
Follow this https://github.com/EllisLab/CodeIgniter/wiki/CodeIgniter-2.1-internationalization-i18n
its simple and clear, also check out the document # http://ellislab.com/codeigniter/user-guide/libraries/language.html
its way simpler than
I am using such code in config.php:
$lang = 'ru'; // this language will be used if there is no any lang information from useragent (for example, from command line, wget, etc...
if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) $lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'],0,2);
$tmp_value = $_COOKIE['language'];
if (!empty($tmp_value)) $lang = $tmp_value;
switch ($lang)
{
case 'ru':
$config['language'] = 'russian';
setlocale(LC_ALL,'ru_RU.UTF-8');
break;
case 'uk':
$config['language'] = 'ukrainian';
setlocale(LC_ALL,'uk_UA.UTF-8');
break;
case 'foo':
$config['language'] = 'foo';
setlocale(LC_ALL,'foo_FOO.UTF-8');
break;
default:
$config['language'] = 'english';
setlocale(LC_ALL,'en_US.UTF-8');
break;
}
.... and then i'm using usualy internal mechanizm of CI
o, almost forget! in views i using buttons, which seting cookie 'language' with language, prefered by user.
So, first this code try to detect "preffered language" setted in user`s useragent (browser). Then code try to read cookie 'language'. And finaly - switch sets language for CI-application
you can make a function like this
function translateTo($language, $word) {
define('defaultLang','english');
if (isset($lang[$language][$word]) == FALSE)
return $lang[$language][$word];
else
return $lang[defaultLang][$word];
}
Friend, don't worry, if you have any application installed built in codeigniter and you wanna add some language pack just follow these steps:
1. Add language files in folder application/language/arabic (i add arabic lang in sma2 built in ci)
2. Go to the file named setting.php in application/modules/settings/views/setting.php. Here you find the array
<?php /*
$lang = array (
'english' => 'English',
'arabic' => 'Arabic', // i add this here
'spanish' => 'EspaƱol'
Now save and run the application. It's worked fine.

Resources