cakephp .po files not being used - php

I'm trying to get CakePHP's i18n component to work. I have extracted my strings to app/Locale/default.pot using the i18n console task. I then copied it into app/Locale/eng/LC_MESSAGES/default.po and app/Locale/fra/LC_MESSAGES/default.po making sure to change the extension. I used the program Virtaal (similar to Poedit) to translate some of the strings.
In my app/Config/core.php I have set my default language to english with Configure::write('Config.language', 'eng'); if I change it to Configure::write('Config.language', 'fra'); I expected to see the new translated strings but nothing changed. I tried setting the Config.language key in the session as well but it didn't do anything. Printing out the configure value and session values I can see they are being set.
Am I missing something here? also in the many different posts I've been reading about i18n in CakePHP I've seen the key fre being used interchangeably with fra is there a difference?

After http://book.cakephp.org/1.3/en/The-Manual/Common-Tasks-With-CakePHP/Internationalization-Localization.html it should be fre for french.
// locale path
/app/locale/fre/LC_MESSAGES/default.po (French)
// To change or set the language for your application, all you need to do is the following:
Configure::write('Config.language', 'fre');
// To set the language for the current user, store the setting in the Session object, like this:
$this->Session->write('Config.language', 'fre');
Further than that:
In our cakePHP application I have to restart the apache webserver after changing the files to get the new strings because of caching. Perhaps you have to do that too, but I'm not quite sure as we generate .mo files out of the .po via an POEdit setting. I dont't think you are forced to do this, because the cookboke doesn't say anything about that (or I didn't found it now :D ).
edit:
Looks like cake is using the bibliographic codes for french but the terminology for german. That's very confusing :/ : http://www.loc.gov/standards/iso639-2/php/code_list.php

Related

Symfony2: How to set default locale and case insensitive translation

I am just starting using symfony2 and facing some difficulty need helps from expert like you guys.
Question 1: How to set the default locale and fallback locale so that people try to hit something like www.example.com/home or www.example.com/fr/home (not supported locale) will redirect to www.example.com/cn/home?
I have read a lot from symfony2 document (http://symfony.com/doc/current/book/translation.html) and also searching on google but I still can't make it works. Not only default locale not working, the fallback locale also not working. For example, when user try to enter www.example.com/fr/home which is not supported by my app, it supposes to redirect the user to www.example.com/cn/home but it fails to do so.
I try to clear cache also but it seem like not working.
Question 2: How to match the translation key in case insensitive?
For example, in my translation file ("message.cn.yml") contains
Welcome: 欢迎
So in my twig template, I use {{ 'Welcome' | trans }} it will help me convert to 欢迎 but when I use {{ 'welcome' | trans }} it will not convert. Is there any ways to make it to case insensitive so I do not need to purposely add in the key "welcome: 欢迎" to the message.cn.yml file.
Your help and suggestion is very much appreciated. Thank you.
Below are my app files for your reference:
Translations file:
Parameters file:
Config file:
Routing file in the particular bundle("Acme/DemoBundle"):
Twig file:
Here is the result when I hit
localhost/locale/web/app_dev.php/
localhost/locale/web/app_dev.php/en
localhost/locale/web/app_dev.php/cn
localhost/locale/web/app_dev.php/fr
You can set locale for a request:
$this->container->get('request_stack')->getCurrentRequest()->setLocale($locale);
and you can set locale per request using a request listener:
http://symfony.com/doc/current/cookbook/service_container/event_listener.html#request-events-checking-types
for your second question you can add conversion to lower case:
{{ 'WELCOME'|lower | translate}}
or you can create your own customized twig extension that is doing the translation and other stuff in between:
http://symfony.com/doc/current/cookbook/templating/twig_extension.html

Display multilingual error messages

I am using Yii framework to develop a multilingual web site. Right now I have English and French versions. I have created a fr folder and placed views and controllers related to French version, but using same models for both versions.
My database tables structure (articles table) is:
id, title_en, title_fr, title_ru, detail_en, detail_fr, detail_ru and
so on.
The issue I am facing is that I need to display error messages to the users in respective languages like in French version error message should be in French. How can I do while using same model for all languages.
Where do I need to put the French messages?
I don't know, if I'm getting you correct, but if I understand your question, your problem is already solved by core Yii 1.x engine and there isn't much work left to do.
In detail, you have to:
Create any file (for example app.php) in /protected/messages/fr/ folder.
Put 'coreMessages'=>array('basePath'=>'../protected/messages'), to your application's configuration array -- route Yii translation system to folder with your customized translations.
Put 'sourceLanguage'=>'en' to your configuration array -- make sure, that your applications's core language is set to English.
Fill app.php file with your translation strings (see below).
Translate parts of your application with Yii::t('app', 'string'); (see below).
Your translation files should be in format:
return array
(
//Translations from Google Translate! :> I don't speak French at all! :>
'This page is not yet translated into your language.'=>'Cette page n'a pas encore été traduit dans votre langue.',
'Language'=>'Langue',
'read more'=>'en savoir plus'
);
So, for example, but in your blog list view string like:
<?php Yii::t('app', 'read more'); ?>
When you set your application language to fr, either by forcing it in code (Yii::app()->language = 'fr';) or presetting it in appliction's configuration array ('language'=>'fr'), you should see en savoir plus (or whatever you put to your translation file) in place of read more in above view.
If your application's language is set back to English or if given translation string is not found, you'll see text written in Yii::t. That's why it is so important to use fully qualified English strings in this method (and in translation files) and to avoid "patterns", like 'core.app.language'=>'Langue' etc.
Note, that you can also use parameter placeholders:
'Error no {code}:'=>'Erreur n {code}:'
that will be replaced with the actual parameter values:
Yii::t('app', 'Error no {code}:', array('{code}'=>$code));
This way you can provide variable values to otherwise constant message text.
There's a great topic about internationalization in "The Definitive Guide to Yii". You should read it through for more information on this matter or, if you want to use Yii translation mechanism in a bit more advanced way.
You can override CPhpMessageSource::loadMessages() with something like following:
protected function loadMessages($category,$language)
{
if ($category == 'yii')
return array();
else
return parent::loadMessages($category,$language);
}
Also You can change the language, set CApplication::language appropriately. This can be done at runtime as in
Yii::app()->language = 'fr';

Trying to set symfony locale to something else than fr and en_US

I am trying to make a multi-language application on Symfony2 and I was wondering why when I use this $this->get('session')->setLocale('fr'); it works (finds the file /src/ggirtsou/MyBundle/Resources/Translations/messages.fr.xliff) but when I set it to something like: el_GR it won't work.
I tried many variations (el, GR, EL, GR_el) but none of them worked. Kept getting the non-translated string.
I know I am missing something here and can't figure this out!
Make sure you have messages.gr.xliff file in Resources/Translations folder. After adding languages always clear the cache.

Best way to internationalize simple PHP website

I have to develop a pretty simple php website so I don't need framework.
But it's must support multi language (EN/FR/CHINESE).
I have looked for php built in system and I found two ways :
intl module from php5.3 (http://php.net/manual/fr/book.intl.php)
gettext (http://php.net/manual/fr/book.gettext.php)
I have no experience in i18n without framework, so any advices about what's the simplest way to support multi language ?
At end I just need a function that search translation into file (one file by language).
EQ :
trans('hello');
=> en.yaml (yaml or not, it's an example)
hello: "Hello world!"
=> fr.yaml
hello: "Bonjour tout le monde !"
And if possible I prefer Pure PHP implementations
Although ext/gettext and ext/intl are both related to i18 (internationalization), gettext deals with translation while intl deals with internationalizing things like number and date display, sorting orders and transliteration. So you'd actually need both for a complete i18-solution. Depending on your needs you may come up with an home-brew solution relying on the extensions mentioned above or your use components provided by some framework:
Translation
Symfony 2 Translation component: https://github.com/symfony/Translation
Zend Framework Zend_Translate
Internationalization
Zend Framework Zend_Locale
If you only need translation and the site is simple enough, perhaps your simple solution (reading a translation configuration file into an PHP array, using a simple function to retrieve a token) might be the easiest.
The most simple solution I can think of is:
$translation = array(
'Hello world!' => array(
'fr' => 'Bonjour tout le monde!',
'de' => 'Hallo Welt!'
)
);
if (!function_exists('gettext')) {
function _($token, $lang = null) {
global $translation;
if ( empty($lang)
|| !array_key_exists($token, $translation)
|| !array_key_exists($lang, $translation[$token])
) {
return $token;
} else {
return $translation[$token][$lang];
}
}
}
echo _('Hello World!');
I know this is an old question, but I feel that the answers are lacking a more hands-on approach from start to finish. This is what I did to get translation working using PHP's gettext library and Poedit without using any additional PHP libraries on a Debian server:
Preparation step 1: Install gettext and the locales on the server
I am not sure how this is done with other operating systems, but for Debian, you do:
sudo apt-get install gettext
sudo dpkg-reconfigure locales
Edit: I assumed Ubuntu would be the same as Debian, but apparently it's slightly different. See this page for instructions for installing locales on Ubuntu.
Make sure you select all of the locales that you want to use. You should then see something like:
Generating locales (this might take a while)...
en_US.UTF-8... done
es_MX.UTF-8... done
fr_FR.UTF-8... done
zh_CN.UTF-8... done
Generation complete.
Note: Make sure you select the right variants and character encodings (most likely UTF-8) for each language. If you install es_MX.UTF-8 and try to use es_ES.UTF-8 or es_MX.ISO-8859-1 it won't work.
Preparation step 2: Install Poedit on the translators' computers
Poedit is available from the software repository for most Linux operating systems. For Debian-based, just execute:
sudo apt-get install poedit
For Windows and Mac, go to: https://poedit.net/download
Start coding:
Ok, now you're ready to get started coding. I wrote the following gettext() wrapper function to translate both singular and plurals:
function __($text, $plural=null, $number=null) {
if (!isset($plural)) {
return _($text);
}
return ngettext($text, $plural, $number);
}
Example usage:
// Singular
echo __('Hello world');
// Plural
$exp = 3;
printf(
__(
'Your account will expire in %d day',
'Your account will expire in %d days',
$exp
),
$exp
);
This will work for all languages, not only languages where plural is anything where n != 1 - this includes languages with multiple plural types.
You can also add translator notes like this:
/** NOTE: The name Coconut Hotel is a brand name and shouldn't be
translated.
*/
echo __('Welcome to Coconut Hotel');
You can change the text from NOTE to whatever you want, but you will have to alter it in the shell script below. Important: The translators note must be part of a comment on the line immediately preceding the __() function or it won't be picked up when we scan the PHP files for translatable strings.
// Warning! THIS WILL NOT WORK!
/* NOTE: This translator's note will not be picked up because it is
not immediately preceding the __() function. */
printf(
__(
'Your account will expire in %d day',
'Your account will expire in %d days',
$exp
),
$exp
);
// Warning! THIS WILL NOT WORK!
After you are ready to send the strings off to the translators, save the following as a shell script (e.g. update.sh) in your application's root directory:
#!/bin/sh
find . -iname "*.php" | xargs xgettext --add-comments=NOTE --keyword=__:1,2 --keyword=__ --from-code=UTF-8 -o i18n.pot
find . -name '*.po' | xargs -I{} msgmerge -U {} i18n.pot
To execute it, just do:
cd /path/to/script && sh update.sh
This will recursively scan for all PHP files in that directory and create a .pot file (I called it i18n.pot, but feel free to name it whatever you like) and update any existing .po files it finds with the new strings.
We then need to create the directories that all the locale files will be stored, one for each locale. They need to be of the format ./locale/{locale}/LC_MESSAGES. For example:
cd /path/to/your/project
mkdir -p ./locale/en_US.UTF-8/LC_MESSAGES
mkdir -p ./locale/es_MX.UTF-8/LC_MESSAGES
# ...etc.
You need to decide on a text domain to use. This can be anything you want, but the script will look for a file called {yourTextDomain}.mo within the LC_MESSAGES folder for that language. Put the following in your PHP script:
define('TEXT_DOMAIN', 'yourdomain');
bindtextdomain(TEXT_DOMAIN, __DIR__.'/locale');
textdomain(TEXT_DOMAIN);
bind_textdomain_codeset(TEXT_DOMAIN, 'UTF-8');
Then to actually switch to another locale, do:
$lang = 'es_MX.UTF-8'; // Change this to the language you want to use
if (setlocale(LC_ALL, $lang) === false) {
throw new Exception("Server error: The $lang locale is not installed. Please update the server's localisations.");
}
putenv('LC_ALL='.$lang);
Initially, you send the .pot file generated by the script above to the translators. They then open Poedit and click on File > New from POT/PO file. When they save it, they need to save it as {yourTextDomain}.po. The {yourTextDomain} needs to be exactly the same as the text domain you have in your PHP script. When they save it, it will automatically create both the .po file and the .mo file. Both of these need to be saved in that language's LC_MESSAGES directory when they are done translating.
Now when you update the strings in your PHP file, just re-execute the shell script and send the newly updated .po files to the translators. They then translate the strings and both the .po and .mo files need to be re-uploaded.
That's it. It may seem slightly difficult to get set up, but once you have it up and running, it's really easy.
Gettext seems to be what you need.
There is a file by langage (except for the original one) and it's very easy to use :
echo _('Bonjour, ça va ?');
will print Hello , how are you ? in english.
There is some tools with gettext that could scan your php file and search for translatable string (in fact all string in _() or gettext()). Thanks to that you don't have to worry about the different langage file. You just code your website in the original langage and the langage file will automatically created later.
Nevertheless gettext is more a translation tools whereas intl is really an i18n one (number formating for example)
Althought you don't need a framework you can use a framework. The internationalization features in Zend Framework is pretty good and you can just use that part of it instead of using all the parts (including MVC)

custom php function creation and install

I would like to know how to create a php function that can be installed in php
just like the already built in functions like :
rename
copy
The main point I would like to achieve is a simple php function that can be called from ANY php page on the whole host without needing to have a php function within the php page / needing an include.
so simply I would like to create a function that will work like this :
location();
That without a given input string will output the current location of the file via echo etc
Well, there are a couple of options here. One of them is to actually extend the language by writing an extension. You'd have to muck around with the PHP source code, write it in C, and deal with the Zend Engine internally. You probably wouldn't be able to use this on a shared host and it would be quite time consuming and probably not worth it.
What I would do is put all of your functions into a separate PHP file, say helper_functions.php. Now, go into your php.ini and add the directive: auto_prepend_file = helper_functions.php. This file should be in one of the directories specified in your include_path (that's a php.ini directive too).
What this does is basically automatically put include 'helper_functions.php'; on every script. Each and every request will have these functions included, and you can use them globally.
Read more about auto_append_file.
As others have said, there's probably an easier, better way to do most things. But if you want to write an extension, try these links:
http://docstore.mik.ua/orelly/webprog/php/ch14_01.htm
http://www.tuxradar.com/practicalphp/2/3/0
So you want to extend PHP's core language to create a function called location(), written in C, which could be done in PHP by:
echo __FILE__;
Right. Have fun doing that.

Categories