My b2evolution Version: 1.9.x
This isn't exhaustive but here is a how-to on getting b2evolution to display alternate languages properly. I have used these steps to help get b2evolution posting in Russian and Arabic and should work for other languages as well.
*** This information applies specifically to 1.9.x ***
Typical cause:
The primary cause of foreign language posting problems is caused by bad character set and collation settings in your database. A typical install of MySQL tends to default to Latin1 character set which does not support non-English languages well. When MySQL sees text that is not in its character set it tries to translate it from the original character set to Latin1 and the result is posts that are full of ???????.
Step One
The first step is to fix your /conf/_locales.php. In this example all of the comments have been removed and I have set my default locale to English/US. This will work for you regardless of your actual locale because the real problem we are addressing is character set translation.
Some of these settings may require reasonably current installations of MySQL which you should already have.
Modified section of _locales.php.
$use_l10n = 2;
$evo_charset = '';
$force_io_charset_if_accepted = 'utf-8';
$db_config['connection_charset'] = 'utf8';
$default_locale = 'en-US';
Now that your _locales.php is configured we have two choices. Fix an existing site or start over.
Start over/a new installation.
Drop your database and create a one. Don't neglect this step because it will come back to haunt you. With the new _locales.php in place you will get a database this is capable of displaying posts in other languages.
An existing installation.
Copy this file and change the items marked as YOUR, they are your MySQL user name, password and database. Once you have verified your settings copy it to your server. I didn't write this code, just modified it a little.
<?php
$conn = mysql_connect("localhost", "YOURDBUSER", "YOURDBPASSWORD");
$printonly=true; //change this to false to alter on the fly
$charset="utf8";
$collate="utf8_unicode_ci";
$altertablecharset=true;
$alterdatabasecharser=true;
function PMA_getDbCollation($db)
{
$sq='SHOW CREATE DATABASE `'.$db.'`;';
$res = mysql_query($sq);
if(!$res) echo "\n\n".$sq."\n".mysql_error()."\n\n"; else
if($row = mysql_fetch_assoc($res))
{
$tokenized = @explode(' ', $row[1]);
unset($row, $res, $sql_query);
for ($i = 1; $i + 3 < count($tokenized); $i++)
{
if ($tokenized[$i] == 'DEFAULT' && $tokenized[$i + 1] == 'CHARACTER' && $tokenized[$i + 2] == 'SET')
{
if (isset($tokenized[$i + 5]) && $tokenized[$i + 4] == 'COLLATE')
{
return array($tokenized [$i + 3],$tokenized[$i + 5]); // We found the collation!
}
else
{
return array($tokenized [$i + 3]);
}
}
}
}
return '';
}
?>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1251<? //remember to change it if needed ?>" />
<xmp>
<?php
$rs2 = mysql_query("SHOW DATABASES LIKE 'YOURDBTOFIX'");
if(!$rs2) echo "\n\n".$sq."\n".mysql_error()."\n\n"; else
while ($data2 = mysql_fetch_row($rs2))
{
$db=$data2[0];
$db_cha=PMA_getDbCollation($db);
if ( $db!='mysql' /* &&( $db=='mydb_x' || $db=='mydb_y' ) */ ) // limit to database(s) - $db=='mydb_x' || $db=='mydb_y' || $db=='mydb_z'
if ( @substr($db_cha[0],0,4)!='utf8' ) // limit to charset
{
mysql_select_db($db);
$rs = mysql_query("SHOW TABLES");
if(!$rs) echo "\n\n".$sq."\n".mysql_error()."\n\n"; else
while ($data = mysql_fetch_row($rs))
{
$rs1 = mysql_query("show FULL columns from $data[0]");
if(!$rs1) echo "\n\n".$sq."\n".mysql_error()."\n\n"; else
while ($data1 = mysql_fetch_assoc($rs1))
{
if(in_array(array_shift(split("\\(",$data1['Type'],2)),array(
//'national char',
//'nchar',
//'national varchar',
//'nvarchar',
'char',
'varchar',
'tinytext',
'text',
'mediumtext',
'longtext',
'enum',
'set'
)))
{
if(substr($data1['Collation'],0,4)!='utf8') // limit to charset
{
$sq="ALTER TABLE `$data[0]` CHANGE `".$data1['Field'].'` `'.$data1['Field'].'` '.$data1['Type'].' CHARACTER SET binary '.($data1['Default']==''?'':($data1['Default']=='NULL'?' DEFAULT NULL':' DEFAULT \''.mysql_escape_string($data1['Default']).'\'')).($data1['Null']=='YES'?' NULL ':' NOT NULL').';';
if(!$printonly&&!mysql_query($sq)) echo "\n\n".$sq."\n".mysql_error()."\n\n";
else
{
echo ($sq."\n") ;
$sq="ALTER TABLE `$data[0]` CHANGE `".$data1['Field'].'` `'.$data1['Field'].'` '.$data1['Type']." CHARACTER SET $charset ".($collate==''?'':"COLLATE $collate").($data1['Default']==''?'':($data1['Default']=='NULL'?' DEFAULT NULL':' DEFAULT \''.mysql_escape_string($data1['Default']).'\'')).($data1['Null']=='YES'?' NULL ':' NOT NULL').($data1['Comment']==''?'':' COMMENT \''.mysql_escape_string($data1['Comment']).'\'').';';
if(!$printonly&&!mysql_query($sq)) echo "\n\n".$sq."\n".mysql_error()."\n\n";
else echo ($sq."\n") ;
}
}
}
}
if($altertablecharset)
{
/*
$sq='ALTER TABLE `'.$data[0]."` DEFAULT CHARACTER SET binary";
echo ($sq."\n") ;
if(!mysql_query($sq)) echo "\n\n".$sq."\n".mysql_error()."\n\n";
*/
$sq='ALTER TABLE `'.$data[0]."` DEFAULT CHARACTER SET $charset ".($collate==''?'':"COLLATE $collate");
echo ($sq.";\n") ;
if(!$printonly)
if(!mysql_query($sq)) echo "\n\n".$sq."\n".mysql_error()."\n\n";
}
}
if($alterdatabasecharser)
{
/*
$sq='ALTER DATABASE `'.$data2[0]."` DEFAULT CHARACTER SET binary";
echo ($sq."\n") ;
if(!mysql_query($sq)) echo "\n\n".$sq."\n".mysql_error()."\n\n";
*/
$sq='ALTER DATABASE `'.$data2[0]."` DEFAULT CHARACTER SET $charset ".($collate==''?'':"COLLATE $collate;");
echo ($sq."\n") ;
if(!$printonly)
if(!mysql_query($sq)) echo "\n\n".$sq."\n".mysql_error()."\n\n";
}
}
}
?>
</xmp>
Run the script. In my example it is http://localhost/install/fixcharset.php
This script will take some time to execute and may even time out if your install of PHP have a short script execution time. When it is finished it will generate a list of ALTER statements that can be used to fix your existing database. All you need to do is copy these commands into the SQL window of phpMyAdmin and execute them.
If you don't have phpMyAdmin then you can change the line $printonly = true; to $printonly = false; and copy the script to your server and run it again. This will run the ALTER statements against your database.
If the script fails to execute properly you can always run just this next piece but it will not fix all your problems, just the ones that directly involve posting.
ALTER TABLE `evo_item__prerendering` CHANGE `itpr_format` `itpr_format` enum('htmlbody','entityencoded','xml','text') CHARACTER SET binary NOT NULL;
ALTER TABLE `evo_item__prerendering` CHANGE `itpr_format` `itpr_format` enum('htmlbody','entityencoded','xml','text') CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL;
ALTER TABLE `evo_item__prerendering` CHANGE `itpr_renderers` `itpr_renderers` text CHARACTER SET binary NOT NULL;
ALTER TABLE `evo_item__prerendering` CHANGE `itpr_renderers` `itpr_renderers` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL;
ALTER TABLE `evo_item__prerendering` CHANGE `itpr_content_prerendered` `itpr_content_prerendered` text CHARACTER SET binary NULL ;
ALTER TABLE `evo_item__prerendering` CHANGE `itpr_content_prerendered` `itpr_content_prerendered` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL ;
ALTER TABLE `evo_item__prerendering` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
ALTER TABLE `evo_posts` CHANGE `post_status` `post_status` enum('published','deprecated','protected','private','draft') CHARACTER SET binary DEFAULT 'published' NOT NULL;
ALTER TABLE `evo_posts` CHANGE `post_status` `post_status` enum('published','deprecated','protected','private','draft') CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT 'published' NOT NULL;
ALTER TABLE `evo_posts` CHANGE `post_locale` `post_locale` varchar(20) CHARACTER SET binary DEFAULT 'en-EU' NOT NULL;
ALTER TABLE `evo_posts` CHANGE `post_locale` `post_locale` varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT 'en-EU' NOT NULL;
ALTER TABLE `evo_posts` CHANGE `post_content` `post_content` text CHARACTER SET binary NULL ;
ALTER TABLE `evo_posts` CHANGE `post_content` `post_content` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL ;
ALTER TABLE `evo_posts` CHANGE `post_title` `post_title` text CHARACTER SET binary NOT NULL;
ALTER TABLE `evo_posts` CHANGE `post_title` `post_title` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL;
ALTER TABLE `evo_posts` CHANGE `post_urltitle` `post_urltitle` varchar(250) CHARACTER SET binary NULL ;
ALTER TABLE `evo_posts` CHANGE `post_urltitle` `post_urltitle` varchar(250) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL ;
ALTER TABLE `evo_posts` CHANGE `post_url` `post_url` varchar(255) CHARACTER SET binary NULL ;
ALTER TABLE `evo_posts` CHANGE `post_url` `post_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL ;
ALTER TABLE `evo_posts` CHANGE `post_notifications_status` `post_notifications_status` enum('noreq','todo','started','finished') CHARACTER SET binary DEFAULT 'noreq' NOT NULL;
ALTER TABLE `evo_posts` CHANGE `post_notifications_status` `post_notifications_status` enum('noreq','todo','started','finished') CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT 'noreq' NOT NULL;
ALTER TABLE `evo_posts` CHANGE `post_comment_status` `post_comment_status` enum('disabled','open','closed') CHARACTER SET binary DEFAULT 'open' NOT NULL;
ALTER TABLE `evo_posts` CHANGE `post_comment_status` `post_comment_status` enum('disabled','open','closed') CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT 'open' NOT NULL;
ALTER TABLE `evo_posts` CHANGE `post_renderers` `post_renderers` text CHARACTER SET binary NOT NULL;
ALTER TABLE `evo_posts` CHANGE `post_renderers` `post_renderers` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL;
ALTER TABLE `evo_posts` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
Notes:
1. While this has worked for me and other people, you may encounter a problem that I have not anticipated. If so, please ask and I will see if I can help.
2. Any post that was scrambled before the change will still be scrambled because MySQL did a charset conversion when the post was saved.
3. You must at the very least fix the posts table and the pre-rendering table because it is ultimately used to display posts.
4. Failure to address the other tables will cause odd displaying of comments, categories, etc. so please don't skip a step.
5. If this doesn't address all the problems, I do have a hack to one file but it may not be necessary so start with this list.
A tip of the hat goes to kskhater. He suggested that I share these tips since this seems to be a problem for a few people. If he hadn't suggested it I would have probably filed this away in the back of my mind and forgotten what I had done to get this working.
Thanks smpdawg for the tip of hat, but your work should be admired by everyone who struggle to get b2evo to perfection.