One of the latest projects I worked on for about a month was developing a social network. The site itself isn't very complex. But there was (and still is) one thing that bothers me — language support. In WordPress, this issue has long been well developed. And if you’re comfortable with using a computer and writing/editing text, translating a theme or plugin is not a big deal. But for a custom CMS, which I use in almost all of my projects, this becomes a problem — especially if language support wasn’t properly thought out from the start.
Naively, I decided to use the localization functionality provided by the Kohana framework (which my engine is based on). By default, phrases and translated words are stored in a standard PHP file as an array. Here’s an example of pagination translation:
return array(
'First' => 'First',
'Last' => 'Last',
'Previous' => '<',
'Next' => '>',
);
The main advantage of this method is performance. Any others? Seems like that’s it. But in high-load projects, it matters! Of course, this method only works well if you don’t plan to expand the site in the future. Or if there’s a tool (or one is developed) to extract `__()` strings into such an array — this approach could work too (I read about this idea on Habr).
But once I imagined how many edits would be required during refinements — and how much time I’d spend on these languages (there are five at the moment!) — I immediately decided to abandon this method.
After some thinking, I came to two conclusions:
- You can use the PHP extension "gettext".
- You can borrow the approach from existing CMSs (WP, Drupal, Joomla).
Started with the first one. Honestly — it wasn’t easy. Locale settings, strange file paths, encoding issues... nothing worked. Plus, the client’s server didn’t even have the gettext extension installed. So I had to drop that idea.
Still, I’ll need to learn gettext properly later.
Option two. Fortunately, I had some experience with WP. So I decided to dig deeper into it.
After analyzing how `load_theme_textdomain()` and `__()` work, I built a simple language-handling class. It was successfully integrated (but not yet fully tested).
How to Connect WordPress POMO to Your Custom Engine
From WordPress, we’ll need 5 files from `/wp-includes/pomo/`:
`entry.php`, `mo.php`, `po.php`, `streams.php`, `translations.php`.
Maybe not all of them are necessary, but since I didn’t study the class logic — I just took everything to be safe.
Below is a class that performs the same tasks as `load_theme_textdomain()` and `__()` in WP:
<?php
class Lng
{
private static $_lang_ar = array();
public static function _($s, $l = 'default', $a = NULL)
{
$l = Lng::l().'-'.$l.'.mo';
if (!isset(Lng::$_lang_ar[$l]))
{
Lng::$_lang_ar[$l] = new NOOP_Translations;
}
$s = Lng::$_lang_ar[$l]->translate($s);
return empty($a) ? $s : strtr($s, $a);
}
public static function load($l, $p)
{
$l = Lng::l().'-'.$l.'.mo';
if (!class_exists('MO', FALSE))
{
throw new Exception('The "MO" library does not included');
}
try {
$MO = new MO();
if (!$MO->import_from_file($p.$l)) {
return FALSE;
}
if (isset(Lng::$_lang_ar[$l])) {
$MO->merge_with(Lng::$_lang_ar[$l]);
}
Lng::$_lang_ar[$l] = &$MO;
}
catch (Exception $e)
{
throw new Exception('The language file "'.$l.'" does not exist');
}
return TRUE;
}
public static function l()
{
return 'ru';
}
}
And here’s a usage example:
<?php
header('Content-Type: text/html; charset=utf-8');
try {
require_once('vendor/pomo/mo.php');
require_once('library/lng.php');
Lng::load('first','languages/');
Lng::load('second','languages/');
}
catch(Exception $e) {
echo $e->getMessage();
}
$name_first = 'Andriy';
$name_second = 'Alexei';
?>
<p><?php echo Lng::_('Hello {name}, how are you?','first',array('{name}' => $name_first))?></p>
<p><?php echo Lng::_('I am fine, thx {name}. And you?','second',array('{name}' => $name_second))?></p>
I don't think this code needs much explanation — the comments speak for themselves. Just keep in mind that your language files should be located in the `languages` folder and named `first` and `second`.
Expected output:
Hello Andriy, how are you? I am fine, thx Alexei. And you?
Good luck with your translations!
