Language Class – Database

Well, the other day I was looking around in CodeIgniter’s User Guide, and noticed it utilized a simple dynamic language class.

Well, as great as that is… not everyone on the sites I’m using CodeIgniter on is a developer, or even has any knowledge/access to change these files.

So I go to thinking… and eureka! Make it so that if the file_system can’t find the text called, than look in a database table.


Step 1: Create the Table


We’re going to have to create a table in order for the language to be thrown on to.

-- ----------------------------
-- Table structure for language
-- ----------------------------
CREATE TABLE `language`
(
 `id` INT(10) NOT NULL auto_increment,
 `key` VARCHAR(255) collate utf8_unicode_ci NOT NULL,
 `language` VARCHAR(255) collate utf8_unicode_ci NOT NULL DEFAULT 'english',
 `set` VARCHAR(255) collate utf8_unicode_ci DEFAULT NULL,
 `text` longtext collate utf8_unicode_ci,
 PRIMARY KEY (`id`)
)
ENGINE = MyISAM AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8 COLLATE = utf8_unicode_ci CHECKSUM = 1

Feel free to tweak this how you see fit… though keep in mind you will have to change the object or array calls in the class to reflect it.

Now download and install this file into your ../application/libraries/ directory, and make sure that the MY_ on both the file name and the class is what your …/application/config/config.php :: subclass_prefix is set to. (MY_ is default)

Class MY_Language extends CI_Language {
	var $language	= array();
	var $is_loaded	= array();
	var $idiom;
	var $set;
	var $line;
	var $CI;
	function __construct()
	{
		parent::CI_Language();
	}
	/**
	 * Load a language file
	 *
	 * @access	public
	 * @param	mixed	the name of the language file to be loaded. Can be an array
	 * @param	string	the language (english, etc.)
	 * @return	mixed
	 */
	function load($langfile = '', $idiom = '', $return = FALSE)
	{
		// Calling early before CI reformats them
		$this->set = $langfile;
		$this->idiom = $idiom;
		$langfile = str_replace(EXT, '', str_replace('_lang.', '', $langfile)).'_lang'.EXT;
		if (in_array($langfile, $this->is_loaded, TRUE))
		{
			return;
		}
		if ($idiom == '')
		{
			$CI =& get_instance();
			$deft_lang = $CI->config->item('language');
			$idiom = ($deft_lang == '') ? 'english' : $deft_lang;
			$this->idiom = $idiom;
		}
		// Determine where the language file is and load it
		if (file_exists(APPPATH.'language/'.$idiom.'/'.$langfile))
		{
			include(APPPATH.'language/'.$idiom.'/'.$langfile);
		}
		else
		{
			if (file_exists(BASEPATH.'language/'.$idiom.'/'.$langfile))
			{
				include(BASEPATH.'language/'.$idiom.'/'.$langfile);
			}
			else
			{
				$database_lang =  $this->_get_from_db();
				if ( ! empty( $database_lang ) )
				{
					$lang = $database_lang;
				}else{
					show_error('Unable to load the requested language file: language/'.$langfile);
				}
			}
		}
		if ( ! isset($lang))
		{
			log_message('error', 'Language file contains no data: language/'.$idiom.'/'.$langfile);
			return;
		}
		if ($return == TRUE)
		{
			return $lang;
		}
		$this->is_loaded[] = $langfile;
		$this->language = array_merge($this->language, $lang);
		unset($lang);
		log_message('debug', 'Language file loaded: language/'.$idiom.'/'.$langfile);
		return TRUE;
	}
	/**
	 * Load a language from database
	 *
	 * @access	private
	 * @return	array
	 */
	private function _get_from_db()
	{
        $CI =& get_instance();
		$CI->db->select   ('*');
		$CI->db->from	 ('language');
		$CI->db->where	('language', $this->idiom);
		$CI->db->where	('set', $this->set);
		$query = $CI->db->get()->result();
		foreach ( $query as $row )
		{
			$return[$row->key] = $row->text;
		}
		unset($CI, $query);
		return $return;
	}
}

Per @joseph’s request:

Ok, I had to review my own code and prototypes to verify the usage, lol.

$this->lang->load(‘set’, ‘en’);
$this->lang->load($this->set, $this->idiom);

Set being the common set of language lines to fetch from the database and idiom being the locale (en, cz, jp, etc).

The default usage doesn’t differ from the standard core language class. Only difference is that the first parameter is either seeking the filename in the language directory OR a set within the database.

Sets are simply language records that belong to a common set.

So set would be the set of language keys to load. So if you have 5 language records in your db with ‘home’ as the set and you call.

$this->lang->load(‘home’, ‘cz’);

It will grab all records with set == ‘home’ and language == ‘cz’ from the database. I did this because if you don’t specifiy a set it will attempt to load ALL records in your language table into the CI_Language object which could hinder the load times significantly.

12 Responses to “Language Class – Database”

  1. Rolando D says:

    Excellent. This what I need for my site.

  2. gevork says:

    Can you tell me what for is SET column in the table?

  3. steiner says:

    Set would be the language. en, jp, and so on

  4. gevork says:

    language=englis, set=en;
    language=german, set=de ;

    ?????

  5. gevork says:

    Also as I understood we can use in this case both and database values and file values, right?

  6. gevork says:

    cool. can I use this in commercial applications without any legal problems for future?

  7. joseph says:

    It’s seems like really perfect! But please, can i ask you for some more detailed information about implementation? I load this lib with following parameters from my controller:

    $params = array(‘language’ => ‘czech’, ‘set’ => ‘cz’);
    $this->load->library(‘my_language’, $params);

    and after it i trying load some results from database or file in views:

    $this->lang->line(‘key_from_db’);

    but i still can’t load any data to variable

    Thank you

    Regards

    • steiner says:

      I added a little clarification to the bottom of the above article for you Joseph.

      If that doesn’t help let me know, but it should at least point you in the right direction.

Leave a Reply