Nisu

mmGetText

A very simple version of gettext for PHP
Aug 2008 - Full stable version 2.1

by mm AT nisu.org

On this page ..

  1. Abstract
  2. What is this?
  3. Why not gettext?
  4. Tutorial
    1. Beginning ...
    2. First translation.
    3. Setting up ...
    4. Using __().
    5. Using with several files.
  5. Inport/export.
  6. Reference.
    1. function mmIniStr ($mylang)
    2. function mmSetLang ($langs,$def)
    3. function forceLangSession ($lang)
    4. function __ ($mes,$lang='')
  7. Options.
  8. Caveats.
  9. F.A.Q.
  10. Related topics?.

Abstract

The aim of this PHP script is to provide a very simple gettext-like way to work, without external files. PHP i18n in 5 minutes.

What is this?

This is a very smart replacement for gettext under PHP, to build multilingual scripts. We use mmGetText.php to periodically update the strings to be translated. All the stuff is in one source file, so you work with a single and small multilingual program. The gettext function _() has been replaced by __(). Read the following tutorial and enjoy it.

For technical assistence mail me at mm AT nisu.org

Why not gettext?

gettext is an excellent soft for programming with C. To use it under PHP you need:
  • To have it compiled in your php.
  • Set up a lot of directories.
  • Use several external programs to maintain the translations.
  • Use LC_ settings.
  • Do the HTTP ACCEPT_LANGUAGE parsing by yourself.
  • ...
mmGetText is a single tool and does the work in your source code, so if you write a single, small script, using mmGetText you still have a single, small script and nothing more. Also mmGetText determines the most appropriate language for the current execution of your script.

Tutorial

Beginning ...

We start our step.php program with:

<?

echo __("Hello word\n");
  
?>

The function __() is the replacement for the gettext function _().
If we try to run this program, is obvious than a parse error occurs.
Now, we close our editor (or use someone with automatic reloading) and execute:
	php mmGetText.php step.php
	
obtaining:
	You must insert into your source php:
	/* mmGetText start */
	//
	//
	/* mmGetText end */
	
This will set the area where translations and related function will be inserted.
So, we do it, leaving step.php as:

<?

echo __("Hello word\n");

/* mmGetText start */
//
//
/* mmGetText end */
?>

Then, we close our editor, and execute again:
	php mmGetText.php step.php
	
obtaining:
	, "Hello word\n" not translated
	It seems that the call to mmIniStr is missing,
		for example mmSetLang(mmIniStr('en'),'en');
	

First translation. ^

Then, with our editor, we open or reload step.php and we find something like (do not worry, next we explain how to avoid modifying your scripts with our ugly code):

// ************** Here the translations




  /* new */
    
"Hello word\n" => array( ),





// ************** Here the translations

Then, we do some translation, for example to Spanish and French, changing:
array( )
by
array("es" => "Hola mundo\n", 'fr' => "Bon jour, monde\n" )

We save the file, exit from editor and re-run:
	php mmGetText.php step.php
	
You will obtain:
	It seems that the call to mmIniStr is missing,
		for example mmSetLang(mmIniStr('en'),'en');
	
We open step.php and we find:

array(
    
"Hello word\n" => array(
      
'es' => "Hola mundo\n",
      
'fr' => "Bon jour, monde\n", ),
   );
  

Setting up ... ^

Then we substitute:

<?

echo __("Hello word\n");

by

<?

// my program is written in english 'en'
$availableLangs=mmIniStr('en');
// I set the language of the current execution, defaulting to 'en'
mmSetLang($availableLangs,'en');

echo
__("Hello word\n");
echo
__("Water\n");


The variable $availableLangs is not necessary. After the execution of mmSetLang, a new variable, named $whichLang has been defined, containing the default language for the current execution of the program, you do not need to use it, but you can do it. Also, the variable named $lang_lang is defined by mmIniStr, but you should not modify it at runtime.
Now, we close the editor and we re-run:
	php mmGetText.php step.php
	
obtaining:
	fr, "Water\n" not translated
	
The source code has been modified to:
array(
    
"Hello word\n" => array(
      
'es' => "Hola mundo\n",
      
'fr' => "Bon jour, monde\n", ),
  
/* new */
    
"Water\n" => array(
      
'es' => "",
      
'fr' => "", ),
   );
  

Then we can insert our translations, and so, on.

Using __(). ^

The use of __() is trivial, but here you are some ideas. For example, the no-multilingual expression:

echo "<h3>Some string $somevar other string</h3>";

cannot be rewritten as:

echo __("<h3>Some string $somevar other string</h3>");

because the string to be translated cannot be variable.
Instead, it can be rewritten as:

echo "<h3>".__("Some string ").$somevar.__(" other string")."</h3>";

where HTML code has been deliberately left out of the call.
Or better:

echo "<h3>".sprintf(__("Some string %s other string"),$somevar)."</h3>";

because, by syntactical reasons, in some translations the position of $somevar may be very different from the original.

Using with several files.

If you are building a project involving several php files, you can use mmGetText with every one (obvious). Also you can build a translation file and include it from the rest of php files. To do it:
  1. Build a php file containing only <? mmIniStr( ... ); mmSetLang ( ... ); ?>, i.e. lang.php.
  2. Write your php files using __().
  3. Include lang.php at the beginning of every file.
  4. Run:
    php mmGetText.php lang.php onefile.php otherfile.php ...
Then, mmGetText affects only to the first parameter (lang.php in the example), but reads strings from all the files.

Inport/export. ^

You can import/export from the original 'po' getText format. Executing:
php mmGetText.php -a ca file1.php file2.php  ...
Will produce a file called file1.php.ca.po containing the translations for the lannguaje 'ca' in getText format. Executing:
php mmGetText.php -d ca somefile.po lang.php onefile.php otherfile.php ...
Will update lang.php, merging with the 'ca' translations taken from somefile.po in getText format.

Reference. ^

function mmIniStr ($mylang)

Called to set up then global var $lang_lang. You should not modify this var, you do not need use it.
Parameter $mylang is the language in which the program is written. Returns an array with the available languages in the form ( $def => 1 , first trans => 2, second trans => 2 ).

function mmSetLang ($langs,$def)

Determines the language of the current execution. Language is negotiated with browser. If no match is found, the LC_LANG is inspected. If no match is found, use the $def parameter.
Parameters: $langs: the result to calling mmIniStr; $def: default lang if not match. Does not return nothing, sets $whichLang and $altLang.

function forceLangSession ($lang)

This function allows force language, if called, must be before mmSetLang.
If parameter $lang is set, then set it in $_SESSION.
Then if $_SESSION is set (now or previously), force $whichLang. Example:

forceLangSession($_GET['lang']);
mmSetLang(mmIniStr('en'),'en');

function __ ($mes,$lang='')

Does runtime translation.
Parameters: $mes: the message to be translated; $lang: optional, use it if a different language than detected is needed.

Options.

  • -c
    Compact: Generate translations in a compact mode, not suitable for editing. Original mode can be recovered re-running without -c .
  • -p
    Purge: Remove unused strings, use with care.
  • -g
    Do not guess for modified strings.
  • -h size
    Hashes strings with length greater than size, def 70.
  • -a languaje
    Export languaje to gettext 'po' format.
    Does nothing more
  • -d languaje file.po
    Merges languaje from gettext 'po' format.
    Implies -h 2147483647

Caveats.

mmGetText string detection is based in regular expressions, so it can fail:
  • if the source program has syntactic problems on strings definition (detected in the 99% of cases),
  • if you use sophisticated (unnecessary and inappropriate) strings.
So after using it, you should verify that your program still compiles and works. If it does not, mmGetText.php keeps a copy of your source code as file~ .

F.A.Q. ^

  • How to add a new language?.

    Edit source file and manually add a new language to any of the translated strings. The re-run mmGetText.php and edit again the source file. You will find all the strings ready to be translated to the new language. The non translated strings are displayed by __() literally (untranslated), so you are not forced to translate it immediately.
  • How to avoid warnings from mmGetText for untranslated strings?.

    Use "0" as the translation string.
  • How to avoid interference with included scripts?.

    If some script that uses mmGetText can include another script that also includes mmGetText, a problem with redefinition of functions will occur. To avoid it, in the parent script, you can use:
    /* mmGetText start someprefix */
    that will add someprefix to the names of all functions (so, you must call someprefix__, instead of __). A nice prefix is _.
  • How to automate using vi?

    For unix users, a script like this can help:
    	#!/bin/bash
    	for f in $*; do
    	  vi $f
    	  while true; do
    	    php mmGetText.php $f
    	    [ $? -eq 0 ] && break
    	    [ "$p" ] || p=$[$(vi -c nu -c q $f 2>/dev/null | sed -ne "s/[^0-9 ].*//p")")]
    	    vi +1 +/'\/\/ \(absent\|new\|not completed\|guess\)' $f
    	  done
    	  [ "$p" ] && vi +$p -c q $f && p=''
    	done
    	
    Call the script with the names of the php files to edit.
Select Style - Legal