cakephp multilingual dynamic content from database - php

I want to develop website with option to select language
at the time I do not know about how to structure my database tables i.e
either I should add separate fields for each language e.g
tbl_posts
id, title_en,title_fr,description_en,description_fr,....
or should I get help of google translate at run time
or there is something else easy to do this
secondly I will need to have URLs like
www.domain.com/en/posts/ & www.domain.com/fr/posts/
third what other things should I keep in mind to develop multilingual website.
looking for standardized, more optimized, easy manageable and fully dynamic solution.

Cakephp
Step 1: In your lib/Cake/basic.php add function
if (!function_exists('__dbt')) {
function __dbt($text, $args = null) {
if($text==null){
return null;
}else{
$languageUse = Configure::read('Config.language');
if($languageUse!='en-us' && $languageUse!='eng'){
$modelName = ucfirst($languageUse)."Translation";
$model = ClassRegistry::init($modelName);
$data = $model->find('first',array('fields'=>array('translation'),'conditions'=>array("text"=>"$text")));
if(!empty($data[$modelName]) && $data[$modelName]['translation']!=''){
return $data[$modelName]['translation'];//die('1');
}else{
// Please copy & paste below code from your basic.php __() function
App::uses('I18n', 'I18n');
$translated = I18n::translate($text);
$arguments = func_get_args();
return I18n::insertArgs($translated, array_slice($arguments, 1));
}
}else{
// Please copy & paste below code from your basic.php __() function
App::uses('I18n', 'I18n');
$translated = I18n::translate($text);
$arguments = func_get_args();
return I18n::insertArgs($translated, array_slice($arguments, 1));
}
}
}
}
Step 2: create table on basis of language you want to use
Note: table name should be prefix locale + _tranlations
example: hin_translations, tha_translations etc.
CREATE TABLE IF NOT EXISTS `hin_translations` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`text` text NOT NULL,
`translation` text NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
In above table add english string in your text column and its translation in translation column.
Step 3: where ever you want to change language string either from database or locale po file just use
__dbt("Write your string here");
:) enjoy your multilingual site

Related

Doctrine 2: columnDefinition ENUM not working

I want to use ENUM in my class but TINYINT in my database. I followed this article: https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/cookbook/mysql-enums.html
In my Mysql table:
CREATE TABLE `side` (
`coated` tinyint(1) DEFAULT NULL COMMENT '0 = Uncoated; 1 = Coated',
);
In my class:
/**
* #ORM\Column(type="string", columnDefinition="ENUM('coated', 'uncoated')")
*/
private $coated = null;
Running the values in PHP I get the real value from database:
0 or 1
I'm wondering if this solution works using Mysql. Hope having a solution, if this won't work the only solution I find is:
public function getCoated() {
if ($this->coated === 0){
return "uncoated";
} elseif ($this->coated === 1) {
return "coated";
} else {
return null;
}
}
Instead of using "TINYINT" I suggest to use "BIT" data type, so that database will only allow storing the values as "0" or "1" to be in safe side.
Your existing:
CREATE TABLE `side` (
`coated` tinyint(1) DEFAULT NULL COMMENT '0 = Uncoated; 1 = Coated'
);
Change it to:
CREATE TABLE `side` (
`coated` BIT DEFAULT NULL COMMENT '0 = Uncoated; 1 = Coated'
);
In "TINYINT" it can also accept the values other than 0/1 that might be create a bug in your application if someone updated your table data to like 2,3,4.

MySQL/PHP Multilanguage form

How can I build multilanguage form with Translations from database using pdo object?
for example, there is my code to create pdo object:
try {
$pdo = new PDO("mysql:host=$servername;dbname=$dbname",$username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo $e->getMEssage();
die();
}
$sql = "SELECT FROM `lang_content` `id`, `:lang`";
$query = $pdo->prepare($sql);
if($query->execute(array(
':lang' => $_GET['lang'].'_content'
))){
// Show content
}
MySQL table structure:
CREATE TABLE `lang_content` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`en_content` VARCHAR(1000) NULL DEFAULT NULL,
`lv_content` VARCHAR(1000) NULL DEFAULT NULL,
`ru_content` VARCHAR(1000) NULL DEFAULT NULL,
PRIMARY KEY (`id`)
)
COMMENT='All translations'
ENGINE=MyISAM
;
MySQL table data example:
id en_content lv_content ru_content
1 MOD KASKO КАСКО
2 MTPL OCTA ОСАГО
And I would like to use it like:
if lang en
<?= $result->1 ?> // Echo MOD
Will return MOD,
<?= $result->2 ?> // Echo MTPL
Will return MTPL
Honestly that is not good practice to do your translation via database. Many big platforms do it through some sort of text format. For example magento does it through csv files.
You could start your development with the following code.
Your Spanish translation file es.csv
'Home', 'Inicio'
'Page 1', 'Pagina 1'
'Page 2', 'Pagina 2'
'Page 3', 'Pagina 3'
The first column of words would be your default language which would be defined within a function.
<a href="#"><?php __("Home"); ?>
Then you would use a switch statement like the one you have on top to capture which language the user choose. The __() function would look something like this. Where input would be "home"
$csv = array_map('str_getcsv', file($file));
// Logic (where it would do the translation)
// It could look for the input in the $cvs variable if it exist then use the next value of the current array. Else keep the text the same.
Your cvs file would need to make the exact words to be translated.

Delete mysql records is not working in codeIgniter

This is my controller function:
function delete_article($title){
if ($this->session->userdata('User') && $this->session->userdata('User') == 'admin#example.com') {
$this->load->model('Article', 'Article', TRUE);
$this->Article->delete_article_db($title);
redirect('admin/user_article');
} else {
redirect('');
}
}
And this is my model function for deleting the database record:
function delete_article_db($title) {
$this->db->where('Title', $title);
$this->db->delete('article');
}
When I run this code, nothing gets deleted. However, the code does not fire any errors or warnings.
This is my MySQL table structure:
CREATE TABLE IF NOT EXISTS `article` (
`Name` text NOT NULL,
`Email` text NOT NULL,
`Phone` text NOT NULL,
`Address` text NOT NULL,
`Literature` text NOT NULL,
`Title` text NOT NULL,
`Submission_Name` text NOT NULL,
`Additional_Name` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
A bit of a wild guess, but looking at your controller method, and the variable names, I'm assuming you're passing the title via url, something like
http://example.com/admin/delete/Title to be deleted
Which leads me to think your query is not working because of encoding of the spaces in the url (or other characters) which won't match the not encoded spaces in your db.
Try with:
function delete_article_db($title) {
$this->db->where('Title', rawurldecode($title) );
$this->db->delete('article');
}

Drupal: module update

I've module and I've update to alter database table, shortly I need to do something like
ALTER TABLE `TABLE` ADD `FIELD` INT UNSIGNED NOT NULL AFTER `SOME_FIELD`
so is there any built in function in Drupal to make this changes I considered db_add_field function didn't work?
Sultan
Using db_add_field()
db_add_field('TABLE', 'FIELD', "VARCHAR( 255 ) NOT NULL DEFAULT '0' AFTER FIELD_2");
The above does not work, for one it leaves out the first argument (the reference to $ret) and the fourth argument will not allow a raw sql query, only a structured array.
What I had to do was this (change hook_update_N to modulename_update_XXXX as per the drupal api documentation of course):
function hook_update_N(&$sandbox) {
// We use update_sql here, instead of db_add_field because we cannot specify
// AFTER in the db_add_field.
$ret = array();
$ret[] = update_sql("ALTER TABLE {table} ADD `FIELD` INT UNSIGNED NOT NULL AFTER `SOME_FIELD`");
return $ret;
}
Hope this helps someone else.

External linking and cakephp's routing engine (multilingual)

I recently build a tiny routing 'extension', that calls the routes from a MySQL table (structure downwards). I think it's worth to be mentioned, that this page runs in multiple languages (German and English). So - relying on the cookie, that's currently set in the client's browser - the corresponding routings get connected.
The problem is, that if the user cannot (externally) be linked to a german content page, if his browser's language cookie was set to the English language (because the english routes got connected).
Does anyone got a proper solution for this? To be honest, I don't really know, how to programmatically extend the Router-class' functionality.
The MySQL table's structure looks like this:
CREATE TABLE `routes` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`language` varchar(5) COLLATE latin1_general_ci NOT NULL DEFAULT 'de',
`route` varchar(64) COLLATE latin1_general_ci NOT NULL,
`controller` varchar(64) COLLATE latin1_general_ci NOT NULL,
`action` varchar(64) COLLATE latin1_general_ci NOT NULL,
PRIMARY KEY (`id`)
)
Use p28n - http://bakery.cakephp.org/articles/view/p28n-the-top-to-bottom-persistent-internationalization-tutorial
It works well, I use it a lot and it's part of my standard build now.
I also have a script that will return translated urls depending on the chosen language. I can't remember where I found the script it's based on, but if it helps I can try to send you a clean version.
EDIT: Okay, here's the bones:
This script will translate urls so that they remain SEO friendly across languages. The language switching and message translation is handled by p28n (above) and po.
Put this line in your app/config/bootstrap.php file:
include_once("translate.php");
Put this as the first line of code in app/config/routes.php:
$fromUrl = translate($fromUrl,true);
Now you need to create the file app/config/translate.php which contains all of the routing information:
function translate($str = null,$total = false)
{
// If this is an RSS route, ignore it and bounce straight out
if (strpos($str,".rss")!==false)
return $str;
$translatetable = array(
'some-url-in-german' => array('/articles/msome-url-in-german',1),
'some-url-in-english' => array('/articles/some-url-in-german',2),
'a-german-article' => array('/posts/a-german-article',1),
'an-english-article' => array('/posts/a-german-article',2)
);
if($str)
{
if($total)
{
$old = explode('/',$str);
$lastone = end($old);
if(empty($lastone)) array_pop($old);
$new = array();
/* translate each part or leave untranslated part */
for($i = 0 ; $i <sizeof($old) ; $i++)
{
$new[$i] = translate($old[$i]);
}
/* construct the translated url. This also adds
a trailing "/" even if it wasn't in the original */
$new_url="";
foreach($new as $n)
{
$new_url .= $n."/";
}
return $new_url;
}
else
{
foreach ($translatetable as $orig => $new)
{
if($str == $orig)
{
$str = $new[0];
switchLanguage($new[1]);
}
}
return $str;
}
}
}
function switchLanguage($lang)
{
if($lang>0)
{
$translatetable = array(
'1' => 'de',
'2'=> 'eng'
);
Configure::write(array('Config.language'=>$translatetable[$lang]));
}
}
It's quite straightforward really - the trick is getting it to feed into CakePHP at the right places. I hope it is of some use to you.

Categories