CVE-2015-10092: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: A vulnerability was found in Qtranslate Slug Plugin up to 1.1.16 on WordPress. It has been classified as problematic. Affected is the function add_slug_meta_box of the file includes/class-qtranslate-slug.php. The manipulation leads to cross site scripting. It is possible to launch the attack remotely. Upgrading to version 1.1.17 is able to address this issue. The name of the patch is 74b3932696f9868e14563e51b7d0bb68c53bf5e4. It is recommended to upgrade the affected component. The identifier of this vulnerability is VDB-222324.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
CVSS v3 base score: 6.1
Published: 2023-03-06T06:15Z
Repository: https://github.com/wp-plugins/qtranslate-slug
Language: PHP
Files changed: assets/css/qts-default.css, assets/css/qts-default.min.css, assets/css/qts-settings.css, assets/js/qts-nav-menu-min.js, assets/js/qts-nav-menu.js, assets/js/qts-settings-upgrade.js, assets/js/qts-settings.js, includes/class-qtranslate-slug-widget.php, includes/class-qtranslate-slug.php, includes/qtranslate-slug-settings-options.php, includes/qtranslate-slug-settings.php, includes/termmeta-core.php, languages/qts-es_ES.po, languages/qts-pt_PT.po, languages/qts.pot, qtranslate-slug.php, readme.txt, version.txt
Commit date: 2015-08-05 17:32:56 +0000
Commit message: fixed XSS and added hability to filter the metabox position

git-svn-id: https://plugins.svn.wordpress.org/qtranslate-slug/trunk@1213627 b8457f37-d9ea-0310-8a92-e5e31aec5664

Diff: diff --git a/assets/css/qts-default.css b/assets/css/qts-default.css
new file mode 100644
index 0000000..c700de0
--- /dev/null
+++ b/assets/css/qts-default.css
@@ -0,0 +1,16 @@
+.qts_type_image .qts_lang_item { 
+    float: left;
+    margin-right: 7px;
+}
+.qts_type_image .qts_lang_item.last-child {
+    margin-right: 0;
+}
+.qts_lang_item{
+    margin-top: 7px;
+    margin-bottom: 7px;
+}
+.qts_both {
+    white-space: nowrap;
+    line-height:1em;
+}
+.qts_both img { margin-right: 4px }
diff --git a/assets/css/qts-default.min.css b/assets/css/qts-default.min.css
new file mode 100644
index 0000000..e8867d1
--- /dev/null
+++ b/assets/css/qts-default.min.css
@@ -0,0 +1 @@
+.qts_type_image .qts_lang_item{float:left;margin-right:7px}.qts_type_image .qts_lang_item.last-child{margin-right:0}.qts_lang_item{margin-top:7px;margin-bottom:7px}.qts_both{white-space:nowrap;line-height:1em}.qts_both img{margin-right:4px}
\ No newline at end of file
diff --git a/assets/css/qts-settings.css b/assets/css/qts-settings.css
new file mode 100755
index 0000000..16e263b
--- /dev/null
+++ b/assets/css/qts-settings.css
@@ -0,0 +1,42 @@
+/*messages*/
+.error {color:#cc0000;}
+
+.form-table th  {
+	width: 15%;
+	min-width: 15% !important;
+}
+
+.form-table td > span {
+	display: inline-block;
+	min-width: 100px;
+}
+
+.form-table label {
+	display: block;
+	margin-bottom: 8px;
+}
+
+.qts-slug {
+	width: 35%;
+}
+
+#qts-loading {
+	display: none;
+	position: relative;
+	margin-left: 5px;
+	vertical-align: middle;
+}
+
+div.updated.success{
+	border-color: #298e00;
+	background-color: #D4EDC9;
+}
+
+.error a.button-primary {
+	color: white !important;
+	text-decoration: none !important;
+}
+
+.ko {
+	color: #c00;
+}
\ No newline at end of file
diff --git a/assets/js/qts-nav-menu-min.js b/assets/js/qts-nav-menu-min.js
new file mode 100644
index 0000000..95d44e4
--- /dev/null
+++ b/assets/js/qts-nav-menu-min.js
@@ -0,0 +1 @@
+jQuery(document).ready(function(t){function i(){t(".item-title").each(function(){n[t(this).closest("li").attr("id")]=[],n[t(this).closest("li").attr("id")].Title=t(this).find("span").html(),"undefined"==typeof n[t(this).closest("li").attr("id")].Original&&(n[t(this).closest("li").attr("id")].Original=n[t(this).closest("li").attr("id")].Title)}),t(".menu-item").each(function(){this_label=t(this).find("input.edit-menu-item-title"),this_title=t(this).find("input.edit-menu-item-attr-title"),n[t(this).attr("id")][this_label.attr("id")]=this_label.val(),n[t(this).attr("id")][this_title.attr("id")]=this_title.val()})}function e(){regexp=new RegExp("<!--:"+d+"-->(.*?)<!--:-->","i"),t(".item-title").each(function(){(matches=n[t(this).closest("li").attr("id")].Original.match(regexp))&&t(this).closest("li").find(".link-to-original a").text(matches[1])}),regexp2=new RegExp("<!--:"+d+"-->(.*?)<!--:-->","i"),t(".menu-item").each(function(){this_label=t(this).find("input.edit-menu-item-title"),this_title=t(this).find("input.edit-menu-item-attr-title"),"all"===d?(this_label.val(n[t(this).attr("id")][this_label.attr("id")]),this_title.val(n[t(this).attr("id")][this_title.attr("id")])):((matches=n[t(this).attr("id")][this_label.attr("id")].match(regexp2))&&this_label.val(matches[1]),(matches2=n[t(this).attr("id")][this_title.attr("id")].match(regexp2))&&this_title.val(matches2[1]))})}function a(){t(".menu-item").each(function(){this_label=t(this).find("input.edit-menu-item-title"),this_title=t(this).find("input.edit-menu-item-attr-title"),this_label.val(n[t(this).attr("id")][this_label.attr("id")]),this_title.val(n[t(this).attr("id")][this_title.attr("id")]),t(this).find(".link-to-original a").text(n[t(this).closest("li").attr("id")].Original)})}var n=[],s=wpNavMenu.addMenuItemToBottom;wpNavMenu.addMenuItemToBottom=function(t,a){s(t,a),i(),e()};var l=wpNavMenu.addMenuItemToTop;wpNavMenu.addMenuItemToTop=function(t,a){l(t,a),i(),e()};var d=t("#qt-languages :radio:checked").val();i(),e(),t(document).ajaxComplete(function(){d=t("#qt-languages :radio:checked").val(),e()}),t("#qt-languages :radio").change(function(){d=t("#qt-languages :radio:checked").val(),e()}),t(".submit-add-to-menu").click(function(){d=t("#qt-languages :radio:checked").val(),e()}),t(document.body).on("change","input.edit-menu-item-title",null,function(){regexp=new RegExp("<!--:"+d+"-->(.*?)<!--:-->","i");var i=n[t(this).closest("li").attr("id")][t(this).attr("id")],e=t(this).val();regexp.test(i)&&(n[t(this).closest("li").attr("id")][t(this).attr("id")]=i.replace(regexp,"<!--:"+d+"-->"+e+"<!--:-->"))}),t(document.body).on("change","input.edit-menu-item-attr-title",null,function(){regexp=new RegExp("<!--:"+d+"-->(.*?)<!--:-->","i");var i=n[t(this).closest("li").attr("id")][t(this).attr("id")],e=t(this).val();qts_new_string="<!--:"+d+"-->"+e+"<!--:-->","undefined"==typeof i||""==i?(n[t(this).closest("li").attr("id")][t(this).attr("id")]=qts_new_string,t(this).val(qts_new_string)):regexp.test(i)?n[t(this).closest("li").attr("id")][t(this).attr("id")]=i.replace(regexp,qts_new_string):(t(this).val(i+qts_new_string),n[t(this).closest("li").attr("id")][t(this).attr("id")]=i+qts_new_string)}),t(".menu-save").click(function(){a()}),window.onbeforeunload=function(){a()}});
\ No newline at end of file
diff --git a/assets/js/qts-nav-menu.js b/assets/js/qts-nav-menu.js
new file mode 100644
index 0000000..7b96e9b
--- /dev/null
+++ b/assets/js/qts-nav-menu.js
@@ -0,0 +1,167 @@
+jQuery(document).ready(function($){
+	var qts_menuitemlang = [];
+	// Change titles (and values) when user add new item to the menu:
+	var oldAddMenuItemToBottom = wpNavMenu.addMenuItemToBottom;
+	wpNavMenu.addMenuItemToBottom = function( menuMarkup, req ) {
+		oldAddMenuItemToBottom( menuMarkup, req );
+		saveLang();
+		changeTitles();
+	};
+	var oldAddMenuItemToTop = wpNavMenu.addMenuItemToTop;
+	wpNavMenu.addMenuItemToTop = function( menuMarkup, req ) {
+		oldAddMenuItemToTop( menuMarkup, req );
+		saveLang();
+		changeTitles();
+	};
+	
+	// Change titles (and values) when document is ready:
+	var lang = $('#qt-languages :radio:checked').val();
+	saveLang();
+	changeTitles();
+        
+  /**
+  * Change titles when there is a click on pagination
+  * on show all pages tab.
+  * 
+  * It happens when there are a large number of pages.
+  */
+  $( document ).ajaxComplete(function() {
+      lang = $('#qt-languages :radio:checked').val();
+      changeTitles();
+  });
+	
+	// Change titles (and values) when language is changed:
+	$('#qt-languages :radio').change( function() {
+		lang = $('#qt-languages :radio:checked').val();
+		
+		changeTitles();
+	});
+	
+	// Change titles (and values) when new menu is added:
+	$('.submit-add-to-menu').click( function() {
+		lang = $('#qt-languages :radio:checked').val();
+		changeTitles();
+	});
+		
+	// Update original value when user changed a value:
+	$(document.body).on('change', 'input.edit-menu-item-title', null, function() {
+		regexp = new RegExp('<!--:' + lang + '-->(.*?)<!--:-->', 'i');
+		
+		
+		var qts_old_value = qts_menuitemlang[ $(this).closest("li").attr("id") ][ $(this).attr("id")],
+		    qts_new_value = $(this).val();
+		
+		  if( regexp.test(qts_old_value ) ) {
+		    qts_menuitemlang[ $(this).closest("li").attr("id") ][  $(this).attr("id")] = qts_old_value.replace( regexp,'<!--:' + lang + '-->' + qts_new_value + '<!--:-->');  
+		  }
+			
+	});
+	
+	
+	
+	
+	// Update original title="" value when user changed a value:
+	$(document.body).on('change', 'input.edit-menu-item-attr-title', null, function() {
+		regexp = new RegExp('<!--:' + lang + '-->(.*?)<!--:-->', 'i');
+		var qts_old_value = qts_menuitemlang[ $(this).closest("li").attr("id") ][ $(this).attr("id")],
+		    qts_new_value = $(this).val();
+		    qts_new_string = '<!--:' + lang + '-->'+ qts_new_value + '<!--:-->';
+    if(typeof qts_old_value === "undefined"  || qts_old_value == "" ) { 
+      qts_menuitemlang[ $(this).closest("li").attr("id") ][ $(this).attr("id")] =  qts_new_string;
+      $(this).val( qts_new_string );
+	  } else if( regexp.test(qts_old_value ) ) {
+	    qts_menuitemlang[ $(this).closest("li").attr("id") ][  $(this).attr("id")] = qts_old_value.replace( regexp,qts_new_string);
+	  } else {
+	    $(this).val( qts_old_value + qts_new_string );
+	    qts_menuitemlang[ $(this).closest("li").attr("id") ][  $(this).attr("id")] = qts_old_value + qts_new_string;
+	  }
+			
+	});
+	
+	
+	
+	// Change titles (and values):
+	function saveLang() {
+	    $('.item-title').each( function() {
+	      qts_menuitemlang[ $(this).closest("li").attr("id") ] = [];
+	      qts_menuitemlang[ $(this).closest("li").attr("id") ]['Title'] =  $(this).find("span").html();
+	      
+	      if( typeof qts_menuitemlang[ $(this).closest("li").attr("id") ]['Original'] === "undefined" ) {
+	        qts_menuitemlang[ $(this).closest("li").attr("id") ]['Original'] =  qts_menuitemlang[ $(this).closest("li").attr("id") ]['Title'];
+	      }
+      });
+      $('.menu-item').each( function() {
+        
+        this_label = $(this).find('input.edit-menu-item-title');
+        this_title = $(this).find('input.edit-menu-item-attr-title');
+        
+        qts_menuitemlang[ $(this).attr("id") ][this_label.attr("id") ] = this_label.val();
+        qts_menuitemlang[ $(this).attr("id") ][this_title.attr("id") ] = this_title.val();
+        
+      });
+      
+	}
+	// Change titles (and values):
+	function changeTitles() {
+		// Change menu item titles and links (on the right side):
+		// TODO: review, and dump
+		regexp = new RegExp('<!--:' + lang + '-->(.*?)<!--:-->', 'i');
+		$('.item-title').each( function() {
+			  if (matches = qts_menuitemlang[ $(this).closest("li").attr("id") ]['Original'].match(regexp)) {
+          $(this).closest('li').find('.link-to-original a').text( matches[1] );		
+			  }
+			
+		});
+		// Change menu item title inputs (on the right side): Navigation Label, Title Attribute...
+		regexp2 = new RegExp('<!--:' + lang + '-->(.*?)<!--:-->', 'i');
+		$('.menu-item').each( function() {
+		  this_label = $(this).find('input.edit-menu-item-title');
+      this_title = $(this).find('input.edit-menu-item-attr-title');
+		  if( lang === "all") {
+          this_label.val(qts_menuitemlang[ $(this).attr("id") ][this_label.attr("id") ] );
+          this_title.val(qts_menuitemlang[ $(this).attr("id") ][this_title.attr("id") ] );
+      } else {
+               
+        if (matches = qts_menuitemlang[ $(this).attr("id") ][this_label.attr("id") ].match(regexp2)) {
+            this_label.val( matches[1] );
+        }
+		 
+        if (matches2 = qts_menuitemlang[ $(this).attr("id") ][this_title.attr("id") ].match(regexp2)) {
+            this_title.val( matches2[1] ); 
+        }
+			}
+		});
+		
+		// Change menu item checkbox labels (on the left side):
+		// TODO: fix this, not a show stopper
+		/*$('label.menu-item-title').each( function() {
+			var textNode = $(this).contents().get(1);
+		});*/
+	}
+
+	// Restore the original input values:
+	function restoreValues(){ 
+		  
+		  $('.menu-item').each( function() {
+		      
+		    this_label = $(this).find('input.edit-menu-item-title');
+        this_title = $(this).find('input.edit-menu-item-attr-title');
+        
+        this_label.val( qts_menuitemlang[ $(this).attr("id") ][this_label.attr("id") ] );
+        this_title.val( qts_menuitemlang[ $(this).attr("id") ][this_title.attr("id") ] );
+          $(this).find('.link-to-original a').text( qts_menuitemlang[ $(this).closest("li").attr("id") ]['Original']);
+      });
+	}
+	
+	// Just before saving restore the original input values:
+	$('.menu-save').click(function() {
+		restoreValues();
+	});
+
+	// Just before leaving the page (or refresh) restore the original input values:
+	window.onbeforeunload = function(){ 
+		restoreValues();		
+		return;
+	};
+
+});
\ No newline at end of file
diff --git a/assets/js/qts-settings-upgrade.js b/assets/js/qts-settings-upgrade.js
new file mode 100755
index 0000000..66e18c0
--- /dev/null
+++ b/assets/js/qts-settings-upgrade.js
@@ -0,0 +1,69 @@
+jQuery(document).ready(function($) {
+	
+	function _debug(msg) {
+		if(window.console) {
+			console.debug(msg);
+		}
+	}
+	var upgrade_box = $('#qts-upgrade-box'),
+	upgrade_form = $('#qts-upgrade-form'),
+	upgrade_button = $('#qts-upgrade-button'),
+	notice_status = function(_status) {
+		upgrade_box.removeClass().addClass(_status);
+	},
+	block_form = function(_block) {
+		if (_block) {
+			$('#qts-loading').show();
+			upgrade_button.attr('disabled', true);			
+		} else {
+			$('#qts-loading').hide();
+			upgrade_button.attr('disabled', false);
+		}
+
+	},
+	check_types = function(_response) {
+		
+		block_form(false);
+		upgrade_form.find('.message').remove();
+		
+		switch (_response.status) {
+			default:
+			case 0:
+				upgrade_form.prepend('<p class=\'message ko\'>'+_response.message+'</p>');
+			break;
+			case 1:
+				notice_status('updated success');
+				upgrade_form.remove();
+				upgrade_box.append('<p><strong>'+_response.message+'</strong></p>');
+				upgrade_box.delay(2500).fadeTo(1300, 0, function(){ upgrade_box.remove(); });
+			break;
+			case 2:
+				var data_ = '<p class=\'message\'>'+_response.message+'</p>';
+				data_ += '<select id=\'qts-slug-type\' class=\'message\'>';
+				
+				for (opt in _response.options) 
+					data_ += '<option value=\''+opt+'\'>'+_response.options[opt]+'</option>';
+				data_ += '</select>';
+				
+				upgrade_form.prepend(data_);
+				
+			break;
+		}
+	},
+	start_upgrade = function(_event) {
+		_event.preventDefault();
+		
+		notice_status('updated');
+		block_form(true);
+		
+		var package_ = {};
+		package_.action = $('#qts-upgrade-action').val(); 
+		package_.nonce = $('#qts-upgrade-nonce').val();
+		if ( $('#qts-slug-type').length )
+			package_.type = $('#qts-slug-type').val();
+			
+		$.post(ajaxurl, package_, check_types);
+	};
+	
+	upgrade_button.bind('click', start_upgrade);
+});
\ No newline at end of file
diff --git a/assets/js/qts-settings.js b/assets/js/qts-settings.js
new file mode 100755
index 0000000..c86503e
--- /dev/null
+++ b/assets/js/qts-settings.js
@@ -0,0 +1,19 @@
+/*############### Error messages ######################*/	
+jQuery(function(){
+	
+	var error_msg = jQuery("#message p[class='setting-error-message']");
+	// look for admin messages with the "setting-error-message" error class
+	if (error_msg.length != 0) {
+		// get the title
+		var error_setting = error_msg.attr('title');
+		
+		// look for the label with the "for" attribute=setting title and give it an "error" class (style this in the css file!)
+		jQuery("label[for='" + error_setting + "']").addClass('error');
+		
+		// look for the input with id=setting title and add a red border to it.
+		jQuery("input[id='" + error_setting + "']").attr('style', 'border-color: red');
+	}	
+	
+	
+	
+});
\ No newline at end of file
diff --git a/includes/class-qtranslate-slug-widget.php b/includes/class-qtranslate-slug-widget.php
new file mode 100644
index 0000000..9b08aeb
--- /dev/null
+++ b/includes/class-qtranslate-slug-widget.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * QtranslateSlug_Widget class
+ *
+ * @since 1.0
+ */
+class QtranslateSlugWidget extends WP_Widget {
+     
+    function QtranslateSlugWidget() {
+        $widget_ops = array('classname' => 'qts_widget', 'description' => __('Allows your visitors to choose a Language.','qts') );
+        $this->WP_Widget('qtranslateslug', __('Language selector', 'qts'), $widget_ops);
+    }
+    
+    function widget($args, $instance) {
+        extract($args);
+        
+        echo $before_widget;
+        $title = empty($instance['title']) ? __('Language', 'qts') : apply_filters('widget_title', $instance['title']);
+        $hide_title = empty($instance['hide-title']) ? false : 'on';
+        $type = $instance['type'];
+        $short_text = ($instance['short_text'] == 'on') ? true : false ;
+        
+        if( $type!='text' && $type!='image' && $type!='both' && $type!='dropdown' ) $type='text';
+
+        if( $hide_title!='on')
+            echo $before_title . $title . $after_title;
+        
+        qts_language_menu($type, array( 'id' => $this->id, 'short' => $short_text ) );
+        
+        echo $after_widget;
+    }
+    
+    function update($new_instance, $old_instance) {
+        $instance = $old_instance;
+        $instance['title'] = $new_instance['title'];
+        $instance['hide-title'] = $new_instance['hide-title'];
+        $instance['type'] = $new_instance['type'];
+        $instance['short_text'] = $new_instance['short_text'];
+
+        return $instance;
+    }
+    
+    function form($instance) {
+        $instance = wp_parse_args( (array) $instance, array( 'title' => '', 'hide-title' => false, 'type' => 'text' ) );
+        $title = $instance['title'];
+        $hide_title = $instance['hide-title'];
+        $type = $instance['type'];
+        $short_text = isset($instance['short_text']) ? $instance['short_text'] : '';
+ ?>
+        <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:', 'qts'); ?> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($title); ?>" /></label></p>
+        <p><label for="<?php echo $this->get_field_id('hide-title'); ?>"><?php _e('Hide Title:', 'qts'); ?> <input type="checkbox" id="<?php echo $this->get_field_id('hide-title'); ?>" name="<?php echo $this->get_field_name('hide-title'); ?>" <?php echo ($hide_title=='on')?'checked="checked"':''; ?>/></label></p>
+        <p><?php _e('Display:', 'qts'); ?></p>
+        <p><label for="<?php echo $this->get_field_id('type'); ?>1"><input type="radio" name="<?php echo $this->get_field_name('type'); ?>" id="<?php echo $this->get_field_id('type'); ?>1" value="text"<?php echo ($type=='text')?' checked="checked"':'' ?>/> <?php _e('Text only', 'qts'); ?></label></p>
+        <p><label for="<?php echo $this->get_field_id('type'); ?>2"><input type="radio" name="<?php echo $this->get_field_name('type'); ?>" id="<?php echo $this->get_field_id('type'); ?>2" value="image"<?php echo ($type=='image')?' checked="checked"':'' ?>/> <?php _e('Image only', 'qts'); ?></label></p>
+        <p><label for="<?php echo $this->get_field_id('type'); ?>3"><input type="radio" name="<?php echo $this->get_field_name('type'); ?>" id="<?php echo $this->get_field_id('type'); ?>3" value="both"<?php echo ($type=='both')?' checked="checked"':'' ?>/> <?php _e('Text and Image', 'qts'); ?></label></p>
+        <p><label for="<?php echo $this->get_field_id('type'); ?>4"><input type="radio" name="<?php echo $this->get_field_name('type'); ?>" id="<?php echo $this->get_field_id('type'); ?>4" value="dropdown"<?php echo ($type=='dropdown')?' checked="checked"':'' ?>/> <?php _e('Dropdown Box', 'qts'); ?></label></p>
+        <p><label for="<?php echo $this->get_field_id('short_text'); ?>"><?php _e('Show short name (en):', 'qts'); ?> <input type="checkbox" id="<?php echo $this->get_field_id('short_text'); ?>" name="<?php echo $this->get_field_name('short_text'); ?>" <?php checked($short_text, 'on')  ?>/></label></p>
+
+ <?php
+    }
+}
diff --git a/includes/class-qtranslate-slug.php b/includes/class-qtranslate-slug.php
new file mode 100644
index 0000000..e02c3d7
--- /dev/null
+++ b/includes/class-qtranslate-slug.php
@@ -0,0 +1,2696 @@
+<?php
+
+/**
+ * QtranslateSlug class
+ *
+ * @since 1.0
+ */
+class QtranslateSlug {
+    
+    
+    /**
+     * array with old data system
+     *
+     * @var bool
+     *
+     * @since 1.0
+     */
+    private $old_data = null;
+    
+    
+    
+    /**
+     * stores permalink_structure option, for save queries to db
+     *
+     * @var string
+     *
+     * @since 1.0
+     */
+    private $permalink_structure;
+    
+    
+    
+    /**
+     * Stores options slugs from database
+     *
+     * @var array
+     *
+     * @since 1.0
+     */
+    protected $options;
+    
+    
+    
+    /**
+     * Variable used to override the language
+     *
+     * @var string
+     *
+     * @since 1.0
+     */
+    private $lang = false;
+	
+	/**
+	 * variable for current language
+	 */
+    private $current_lang = false;
+    
+    /**
+	 * variable for default language
+	 */
+    private $default_language = false;
+    
+	/**
+     * Array of enabled languages
+     *
+     * @var array
+     *
+     * @since 1.0
+     */
+    private $enabled_languages = array();
+	/**
+     * Array of enabled languages
+     *
+     * @var array
+     *
+     * @since 1.0
+     */
+    private $url_path_mode = "";
+	
+    
+    
+    /**
+     * slug in meta_key name in meta tables
+     *
+     * @var string
+     *
+     * @since 1.0
+     */
+    private $meta_key = "_qts_slug_%s";
+    
+    
+    
+    /**
+     * Array of translated versions of the current url
+     *
+     * @var array
+     *
+     * @since 1.0
+     */
+    private $current_url = array();
+    
+    
+    /**
+     * Variable that contains the prefix for base plugin function names (qtranslate/qtranslate-x)
+     *
+     * @var string
+     *
+     * @since ?
+     */
+    private $plugin_prefix = "";
+	
+	
+    /**
+     * return the current / temp language
+     *
+     * @since 1.0
+     */
+    private function get_lang() {
+        global $q_config;
+        
+        return ($this->lang) ? $this->lang : $q_config['language'];
+    }
+    /**
+     * return the current / temp language
+	 * we store and use it all the way!
+     *
+     * @since 1.1.9
+     */
+    private function get_currentlang() {
+        return $this->current_lang;
+    }
+    /**
+     * return the enabled languages
+	 * we store and use it all the way!
+     *
+     * @since 1.1.9
+     */
+    private function get_enabled_languages() {
+        return $this->enabled_languages;
+    }
+    /**
+     * return the enabled languages
+	 * we store and use it all the way!
+     *
+     * @since 1.1.9
+     */
+    private function get_url_path_mode() {
+        return $this->url_path_mode;
+    }
+    
+    
+    /**
+     * getter: options
+     *
+     * @since 1.0
+     */
+    public function get_options() {
+        $this->set_options();
+        return $this->options;
+    }
+
+    /**
+     * Returns the correct prefix for the function names of the different supported translation plugins.
+     * Will return 'qtranxf_' if qtranslate-x is used, 'qtrans_' otherwise.
+     *
+     * @return string the function name prefix for translation functions from other plugins
+     * @since 1.1.9
+     */
+
+    private function get_plugin_prefix(){
+        
+        return $this->plugin_prefix;
+    }
+    
+    
+    /**
+     * setter: options | permalink_structure
+     *
+     * @since 1.0
+     */
+    public function set_options() {
+
+        if (empty($this->options)) {
+            $this->options = get_option(QTS_OPTIONS_NAME);
+        }
+
+        if (!$this->options) {
+            add_option(QTS_OPTIONS_NAME, array());
+        }
+        
+        if (is_null($this->permalink_structure)) {
+            $this->permalink_structure = get_option('permalink_structure');
+        }
+    }
+    
+    /**
+	 * Sets the prefix for the active fork. See get_plugin_prefix
+	 * @since 1.1.9
+	 *
+	 */
+    private function set_plugin_prefix(){
+        if ('' === $this->plugin_prefix){
+            if (is_plugin_active('qtranslate-x/qtranslate.php')){
+                $this->plugin_prefix = 'qtranxf_';
+            } else {
+                $this->plugin_prefix = 'qtrans_';
+            }
+        }
+    }
+
+    /**
+     * Sets the url path mode based on the qtranslate or fork settings.
+     *
+     */
+
+    private function set_url_path_mode(){
+        if ('' === $this->url_path_mode){
+            if (is_plugin_active('qtranslate-x/qtranslate.php')){
+                $this->url_path_mode = QTX_URL_PATH;
+            } else {
+                $this->url_path_mode = QT_URL_PATH;
+            }
+        }
+    }
+    
+    /**
+     * setter: options | permalink_structure
+     *
+     * @since 1.0
+     */
+    public function save_options($new_options = false) {
+        if (!$new_options || empty($new_options)) {
+            return;
+        }
+        
+        if (count($this->options) != count($new_options)) {
+            return;
+        }
+        
+        update_option(QTS_OPTIONS_NAME, $new_options);
+        $this->options = $new_options;
+    }
+    
+    
+    
+    /**
+     * getter: meta key
+     *
+     * @since 1.0
+     */
+    public function get_meta_key( $force_lang = false ) {
+        global $q_config;
+        
+        $lang = $this->get_lang();
+        
+        if ($force_lang) {
+            $lang = $force_lang;
+        }
+       
+        return sprintf($this->meta_key, $lang); // returns: _qts_slug_en
+    }
+    
+    
+    
+    /**
+     * check dependences for activation
+     *
+     * @since 1.0
+     */
+    static function block_activate() {
+        global $wp_version;
+        
+        include_once( ABSPATH . 'wp-admin/includes/plugin.php' ); 
+        
+        return (
+            version_compare($wp_version, "3.3", "<" ) ||
+                ( !is_plugin_active('qtranslate/qtranslate.php') && 
+                !is_plugin_active('mqtranslate/mqtranslate.php') && 
+                !is_plugin_active('qtranslate-x/qtranslate.php'))
+        );
+    }
+    
+    
+	
+    
+    /**
+     * check if exists qtranslate and do the installation, support multisite
+     *
+     * @since 1.0
+     */
+    public function install() {
+        global $wpdb;
+        
+        if ( self::block_activate() ) {
+            return;
+        }
+        
+        if ( function_exists('is_multisite') && is_multisite() ) {
+
+            if (isset($_GET['networkwide']) && ($_GET['networkwide'] == 1)) {
+                
+                $old_blog = $wpdb->blogid;
+                $blogids = $wpdb->get_col($wpdb->prepare("SELECT blog_id FROM $wpdb->blogs"));
+                foreach ($blogids as $blog_id) {
+                    switch_to_blog($blog_id);
+                    $this->activate();
+                }
+                switch_to_blog($old_blog);
+                return;
+            }
+        }
+        
+        $this->activate();
+    }
+    
+    
+    
+    /**
+     * activates and do the installation
+     *
+     * @since 1.0
+     */
+    private function activate() {
+        global $wp_rewrite;
+
+        $this->set_options();
+        
+        $qts_version = get_option('qts_version');
+        
+        // checks version and do the installation
+        if ( !$qts_version || $qts_version != QTS_VERSION ) {
+            
+            // install termmeta table using functions from Simple-Term-Meta 
+            // ( http://wordpress.org/extend/plugins/simple-term-meta/ )
+            install_term_meta_table();
+            
+            // update installed option  
+            update_option('qts_version', QTS_VERSION);
+        }
+    
+        // regenerate rewrite rules in db
+        add_action( 'generate_rewrite_rules', array(&$this, 'modify_rewrite_rules') );
+        flush_rewrite_rules();
+    }
+  
+    
+
+    /**
+    * register front end styles and enqueue
+    *
+    * @since 1.1.7
+    */
+    public function register_plugin_styles() {
+		wp_register_style( 'qts_front_styles', plugins_url( '/assets/css/qts-default.css', dirname(__FILE__ ) ) );
+        wp_enqueue_style( 'qts_front_styles' );
+    }
+    /**
+    * register minified front end styles and enqueue
+    * 43LC: easier duplicating the function :|
+    * @since 1.1.8
+    */
+    public function register_plugin_styles_min() {
+		wp_register_style( 'qts_front_styles', plugins_url( '/assets/css/qts-default.min.css', dirname(__FILE__ ) ) );
+        wp_enqueue_style( 'qts_front_styles' );
+    }
+
+
+
+    /**
+    * print front end styles
+    *
+    * @since 1.1.7
+    */
+    public function print_plugin_styles() {
+
+        $css_path = dirname(__FILE__).'/assets/css/qts-default.css';
+
+        if (!file_exists($css_path) || !is_readable($css_path)) {
+            return;
+        }
+
+        $default_css_file = file_get_contents($css_path, FILE_USE_INCLUDE_PATH);
+
+        $css = "<style media=\"screen\">\n";
+        $css .= "$default_css_file\n";
+        $css .="</style>\n";
+        echo $css;
+    }
+  
+    
+
+    /**
+     * actions when deactivating the plugin
+     *
+     * @since 1.0
+     */
+    public function deactivate() {
+        global $wp_rewrite;
+        
+        // regenerate rewrite rules in db
+        remove_action( 'generate_rewrite_rules', array(&$this, 'modify_rewrite_rules') );
+        $wp_rewrite->flush_rules();
+    }
+    
+
+
+    /**
+     * admin notice: update your old data 
+     *
+     * @since 1.0
+     */
+    function notice_update(){
+        global $current_screen;
+        
+        if ($current_screen->id != 'settings_page_qtranslate-slug-settings') {
+        
+            echo "<div class=\"updated\">" . PHP_EOL;
+            echo "<p><strong>Qtranslate Slug:</strong></p>" . PHP_EOL;
+            printf("<p>%s <a href=\"%s\" class=\"button\">%s</a></p>", __('Please update your old data to the new system.', 'qts'), add_query_arg(array('page' => 'qtranslate-slug-settings'), 'options-general.php'), __('upgrade now', 'qts')) . PHP_EOL;
+            echo "</div>" . PHP_EOL;
+        }
+    }
+    
+    
+    
+    /**
+     * admin notice: update your old data 
+     *
+     * @since 1.0
+     */
+    function notice_dependences(){
+        global $current_screen;
+        $ornewer=__('or newer','qts');
+        $info_url=admin_url('plugin-install.php?tab=plugin-information');
+        echo '<div class="error">' . PHP_EOL;
+        echo '<p><strong>Qtranslate Slug:</strong></p>' . PHP_EOL;
+        echo '<p>';
+        printf(__('This plugin requires at least %s and either %s, or %s, or %s', 'qts'),'<strong>WordPress 3.3</strong>','<a href="'.$info_url.'&plugin=qtranslate-x&TB_iframe=true" class="thickbox" aria-label="'.__('More information about', 'qts').' '.'qTranslate-X" data-title="qTranslate-X"><strong>qTranslate-X</strong></a> (2.9 '.$ornewer.')','<a href="'.$info_url.'&plugin=mqtranslate&TB_iframe=true" class="thickbox" aria-label="'.__('More information about', 'qts').' '.'mqTranslate" data-title="mqTranslate"><strong>mqTranslate</strong></a> (2.6.2.4 '.$ornewer.')','<a href="'.$info_url.'&plugin=qtranslate&TB_iframe=true" class="thickbox" aria-label="'.__('More information about', 'qts').' '.'qTranslate" data-title="qTranslate"><strong>qTranslate</strong></a> (2.5.8 '.$ornewer.')');
+        echo '</p>' . PHP_EOL;
+        echo '</div>' . PHP_EOL; 
+    }
+    
+    
+    
+    /**
+     * checks if old table 'qtranslate_slug' exists and is not empty
+     * 
+     * @return object | false
+     *
+     * @since 1.0
+     */
+    public function check_old_data() {
+        global $wpdb;
+        
+        if ($this->old_data === false) {
+            return false;
+        }
+                    
+        $table_name = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}qtranslate_slug'");
+            
+        if (!empty($table_name)) {
+            $this->old_data = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}qtranslate_slug");
+        }
+        
+        if ( empty($table_name) || empty($this->old_data) ) {
+            $this->old_data = false;
+        }
+        
+        return $this->old_data;
+    }
+    
+    
+    
+    /**
+     * actions when deactivating the plugin
+     *
+     * @since 1.0
+     */
+    private function check_old_versions() {
+        
+        if ( $this->check_old_data() ) {
+            add_action('admin_notices', array(&$this, 'notice_update'));
+        }
+    }
+    
+    
+    
+    /**
+     * Initialise the Class with all hooks
+     *
+     * @since 1.0
+     */
+    function init() {
+      
+		load_plugin_textdomain( 'qts', false, basename( plugin_dir_path( dirname( __FILE__ ) ) ) . '/languages' );
+        
+        // checking plugin activate
+        if ( self::block_activate() ) {
+            if (is_admin()) {
+                add_action('admin_notices', array(&$this, 'notice_dependences'));
+            }
+            return;
+        }
+    
+        // caching qts options
+        $this->set_options();
+        
+		global $q_config;
+		
+		// until we get  a proper function, this will make it for it.
+		$this->current_lang = $q_config['language'];
+	    $this->enabled_languages = $q_config['enabled_languages'];
+        $this->default_language  = $q_config['default_language'];
+		$this->set_plugin_prefix();
+		$this->set_url_path_mode();
+		
+        if ( is_admin() ) {
+            
+            $this->check_old_versions();
+       
+            
+            // add filters
+            add_filter( 'qts_validate_post_slug', array(&$this, 'validate_post_slug'), 0, 3 );
+            add_filter( 'qts_validate_post_slug', array(&$this, 'unique_post_slug'), 1, 3 );
+            add_filter( 'qts_validate_term_slug', array(&$this, 'validate_term_slug'), 0, 3 );
+            add_filter( 'qts_validate_term_slug', array(&$this, 'unique_term_slug'), 1, 3 );
+            add_filter( 'wp_get_object_terms', array(&$this, 'get_object_terms'), 0, 4 );
+            add_filter( 'get_terms', array(&$this, 'get_terms'), 0, 3 );
+            
+            // admin actions
+            add_action( 'admin_menu', array(&$this, 'add_slug_meta_box') );
+            add_action( 'save_post', array(&$this, 'save_postdata'), 605, 2 );
+            add_action( 'delete_term', array(&$this, 'delete_term'), 0, 3);
+            add_action( 'created_term', array(&$this, 'save_term'), 605, 3);
+            add_action( 'edited_term', array(&$this, 'save_term'), 605, 3 );
+            add_action( 'admin_head', array(&$this, 'hide_slug_box'), 900 );
+            
+            add_action( 'init', array(&$this, 'taxonomies_hooks'), 805 );
+            
+            add_action( 'wp_dashboard_setup', array(&$this, 'remove_dashboard_widgets') );
+            add_action( 'admin_head', array(&$this, 'hide_quick_edit'), 600 );
+            if(!defined('QTRANSLATE_FILE'))
+              add_action( 'admin_init', array(&$this, 'fix_nav_menu') );
+            
+        } else {
+            
+            add_filter( 'request', array(&$this, 'filter_request') );
+
+            // adds external style file
+            $qts_options = $this->get_options();
+            if ( !isset($qts_options[QTS_PREFIX.'styles']) || $qts_options[QTS_PREFIX.'styles'] == "file" ) {
+                add_action( 'wp_enqueue_scripts', array( &$this, 'register_plugin_styles' ) );
+            } elseif ($qts_options[QTS_PREFIX.'styles'] == "minified" ) {
+                add_action( 'wp_enqueue_scripts', array( &$this, 'register_plugin_styles_min' ) );
+            } elseif ($qts_options[QTS_PREFIX.'styles'] == "inline" ) {
+                add_action( 'wp_print_styles', array( &$this, 'print_plugin_styles' ), 20 );
+            }
+        }
+        
+        add_filter( 'query_vars', array(&$this, 'query_vars'));
+        add_action( 'generate_rewrite_rules', array(&$this, 'modify_rewrite_rules') );
+        
+        // remove from qtranslate the discouraged meta http-equiv, inline styles
+        // (including flag URLs) and wrong hreflang links   
+        
+        remove_action('wp_head', $this->get_plugin_prefix() . 'header');
+        if( "qtranxf_" === $this->get_plugin_prefix() ) {
+            remove_action('wp_head', $this->get_plugin_prefix() . 'head');
+        }
+        
+        // add proper hreflang links
+        add_action('wp_head',array(&$this, 'qtranslate_slug_header_extended'));
+        
+        // remove some Qtranslate filters
+        remove_filter( 'page_link',     $this->get_plugin_prefix() . 'convertURL' );
+        remove_filter( 'post_link',     $this->get_plugin_prefix() . 'convertURL' );
+        remove_filter( 'category_link', $this->get_plugin_prefix() . 'convertURL' );
+        remove_filter( 'tag_link',      $this->get_plugin_prefix() . 'convertURL' );
+        
+        add_filter( 'qts_permastruct' , array(&$this, 'get_extra_permastruct'), 0, 2);
+        add_filter( 'qts_url_args',     array(&$this, 'parse_url_args'), 0, 1);
+        add_filter( 'home_url',         array(&$this, 'home_url'), 10, 4);  
+        add_filter( 'post_type_link',   array(&$this, 'post_type_link'), 600, 4 );
+        add_filter( 'post_link',        array(&$this, 'post_link'), 0, 3 );
+        add_filter( '_get_page_link',   array(&$this, '_get_page_link'), 0, 2 );
+        add_filter( 'term_link',        array(&$this, 'term_link'), 600, 3 );
+        
+        add_filter( 'single_term_title', $this->get_plugin_prefix() . 'useTermLib', 805 );
+        add_filter( 'get_blogs_of_user', array(&$this, 'blog_names'), 1  );
+        add_action( 'widgets_init', array(&$this, 'widget_init'), 100 );
+        // Add specific CSS class to body class based on current lang
+        add_filter('body_class', array($this, 'qts_body_class'), 600, 1 );
+        
+        add_filter( 'nav_menu_attr_title', array($this, 'qts_filter_attr_title'), 0, 3 );
+
+
+    }
+      
+     /**
+     * Filters menu link attribute
+     *  
+     * @since 1.1.9
+     */ 
+    function qts_filter_attr_title( $attr_title ) {
+        return $this->qts_quickuse($attr_title);
+    }
+
+
+    /**
+     * Adds proper links to the content with available translations.
+     * Fixes issue #25
+     *  
+     * @global $qtranslate_slug used to convert the url
+     * @global $q_config available languages
+     *
+     * @since 1.1.8
+     */ 
+    public function qtranslate_slug_header_extended(){
+    	if(is_404()) return;
+        
+        //taken from qtx 
+        echo '<link hreflang="x-default" href="'.$this->get_current_url($this->default_language) .'" rel="alternate" />'.PHP_EOL;
+        foreach($this->get_enabled_languages() as $language) {
+
+            if($language != $this->get_currentlang() )
+                echo '<link hreflang="'.$language.'" href="'.$this->get_current_url($language).'" rel="alternate" />'."\n";
+        }
+    }
+    
+
+    /**
+     * Add a class based on the current language
+     * @param array $classes list of classes
+     */
+    public function qts_body_class( $classes ) {
+        // add 'class-name' to the $classes array
+        $classes[] = call_user_func($this->get_plugin_prefix() . 'getLanguage');
+        
+        // return the $classes array
+        return $classes;
+    }
+
+		/**
+     * Finds the translated slug of the given post 
+     * based on: https://wordpress.org/support/topic/permalink-for-other-languages 
+     * @param int $id the post id
+     * @param string $lang which language to look for
+		 * @return string the slug or empty if not found
+     * @author vbkun
+     * @since 1.1.13
+     */ 
+		public function get_slug($id, $lang){
+			$slugArray = get_post_meta( $id, '_qts_slug_'.$lang );
+			return !empty($slugArray) ? $slugArray[0] : "";
+		}
+
+	// TODO: properly test this
+	/**
+	 * Get text in $lang, or in the current lang
+	 *
+	 * @package Qtranslate Slug
+	 * @since 1.1.9
+	 * @param string $text the whole text
+	 * @param string $lang (optional) get the text in this language, or if empty, the current
+	 * @return array the text in the required language
+	 */
+	public function qts_quickuse( $text,$lang='' ){
+	    global $q_config;
+	    $lang = '' == $lang ? $q_config['language'] : $lang;
+	    $parsed_text = call_user_func($this->get_plugin_prefix() . 'getSortedLanguages',$text);
+	    if( !empty($parsed_text[$lang])){
+	      return $parsed_text[$lang];  
+	    }  
+	}
+	
+
+    /**
+     * Adds news rules to translate the URL bases, 
+     * this function must be called on flush_rewrite or 'flush_rewrite_rules' 
+     * 
+     * @param object $wp_rewrite
+     *
+     * @since 1.0
+     */ 
+    public function modify_rewrite_rules() {
+        // do we need this global?	
+        //global $wp_rewrite;
+        
+        // post types rules
+        $post_types = get_post_types( array('_builtin' => false ), 'objects');
+        foreach ( $post_types as $post_type ) {
+            $this->generate_extra_rules( $post_type->name );
+        }
+        
+        // taxonomies rules
+        $taxonomies = $this->get_public_taxonomies();
+        foreach ( $taxonomies as $taxonomy ) {
+            $this->generate_extra_rules( $taxonomy->name );
+        }
+    }
+    
+    
+    
+    /**
+     * Helper: news rules to translate the URL bases
+     * 
+     * @param string $name name of extra permastruct
+     * @param string $type 'post_type' or 'taxonomy'
+     *
+     * @since 1.0
+     */
+    private function generate_extra_rules( $name = false ) {
+        global $wp_rewrite;
+        
+        foreach ($this->get_enabled_languages() as $lang):
+            
+            if ( $base = $this->get_base_slug( $name, $lang) ):
+                
+                $struct = $wp_rewrite->extra_permastructs[$name];
+                
+                if ( is_array( $struct ) ) {
+                    if ( count( $struct ) == 2 )
+                        $rules = $wp_rewrite->generate_rewrite_rules( "/$base/%$name%", $struct[1] );
+                    else
+                        $rules = $wp_rewrite->generate_rewrite_rules( "/$base/%$name%", $struct['ep_mask'], $struct['paged'], $struct['feed'], $struct['forcomments'], $struct['walk_dirs'], $struct['endpoints'] );
+                } else {
+                    $rules = $wp_rewrite->generate_rewrite_rules( "/$base/%$name%" );
+                }
+                
+                $wp_rewrite->rules = array_merge($rules, $wp_rewrite->rules);
+            
+            endif;
+            
+        endforeach;
+    }
+    
+    
+    
+    /**
+     * Helper that gets a base slug stored in options
+     * 
+     * @param string $name of extra permastruct
+     * @return string base slug for 'post_type' and 'language' or false
+     *
+     * @since 1.0
+     */
+    public function get_base_slug($name = false, $lang = false) {
+        
+        if ( !$name || !$lang ) {
+            return false;
+        }
+        
+        if ( taxonomy_exists($name) ) {
+            $type = 'taxonomy';
+        } else if ( post_type_exists($name) ) {
+            $type = 'post_type';
+        } else {
+            return false;
+        }
+        
+        $qts_options = $this->get_options();
+        
+        $option_name = QTS_PREFIX . $type . '_' . $name;
+        
+        if ( !isset($qts_options[$option_name]) || empty($qts_options[$option_name]) ) {
+            return false;
+        }
+        
+        if (isset($qts_options[$option_name][$lang])) {
+            return $qts_options[$option_name][$lang];
+        }
+        
+        return false;
+    }
+    
+    
+    
+    /**
+     * Helper: returns public built-in and not built-in taxonomies
+     * 
+     * @return array of public taxonomies objects
+     *
+     * @since 1.0
+     */
+    private function get_public_taxonomies() {
+        
+        $builtin = get_taxonomies( array( 'public' => true, 'show_ui' => true, '_builtin' => true ), 'object'); 
+        $taxonomies = get_taxonomies( array( 'public' => true, 'show_ui' => true, '_builtin' => false ), 'object' ); 
+        
+        return array_merge( $builtin, $taxonomies );
+    }
+    
+    
+    
+    /**
+     * parse and adds $_GET args passed to an url
+     * 
+     * @param string $url parameters
+     * @param string $lang processed
+     * @return string converted url
+     *
+     * @since 1.0
+     */
+    public function parse_url_args( $url ) {
+        global $q_config;
+
+        if (is_admin()) {
+            return $url;
+        }
+        
+        $url = preg_replace('/&amp;/', '&', $url);
+        
+        // if no permalink structure ads ?lang=en
+        $base_query = parse_url($q_config['url_info']['original_url']);
+        $base_args = isset($base_query['query']) ? wp_parse_args($base_query['query']) : array();
+        
+        if ( empty($this->permalink_structure) || $q_config['url_mode'] == 1 ) {
+            $base_args['lang'] = $this->get_lang();
+
+        }
+
+        // rebuild query with all args
+        $url = add_query_arg($base_args, $url);
+
+        $url = str_replace('/?', '?', $url); // TODO: hack: improve this code
+        $url = str_replace('?', '/?', $url); // TODO: hack: improve this code
+        
+        return $url;
+    }
+    
+    
+    
+    /**
+     * Fix get_page_by_path when querying vars
+     * 
+     * @param $query_vars objec query vars founded
+     * @return object $query_vars processed
+     *
+     * @since 1.0
+     */
+    public function query_vars( $query_vars ) {
+        global $wp, $wp_rewrite;
+
+        $wp->query_vars = array();
+        $post_type_query_vars = array();
+
+        // Fetch the rewrite rules.
+        $rewrite = $wp_rewrite->wp_rewrite_rules();
+
+        if ( ! empty($rewrite) ) {
+            // If we match a rewrite rule, this will be cleared.
+            $error = '404';
+            $wp->did_permalink = true;
+
+            if ( isset($_SERVER['PATH_INFO']) ) {
+                $pathinfo = $_SERVER['PATH_INFO'];
+            } else {
+                $pathinfo = '';
+            }
+            $pathinfo_array = explode('?', $pathinfo);
+            $pathinfo = str_replace("%", "%25", $pathinfo_array[0]);
+            $req_uri = $_SERVER['REQUEST_URI'];
+            $req_uri_array = explode('?', $req_uri);
+            $req_uri = $req_uri_array[0];
+            $self = $_SERVER['PHP_SELF'];
+            $home_path = parse_url(home_url());
+            
+            if ( isset($home_path['path']) ) {
+                $home_path = $home_path['path'];
+            } else {
+                $home_path = '';
+            }
+            $home_path = trim($home_path, '/');
+
+            // Trim path info from the end and the leading home path from the
+            // front. For path info requests, this leaves us with the requesting
+            // filename, if any. For 404 requests, this leaves us with the
+            // requested permalink.
+            $req_uri = str_replace($pathinfo, '', $req_uri);
+            $req_uri = trim($req_uri, '/');
+            $req_uri = preg_replace("|^$home_path|", '', $req_uri);
+            $req_uri = trim($req_uri, '/');
+            if ($GLOBALS['q_config']['url_mode'] == $this->get_url_path_mode()) {
+                $req_uri = preg_replace("/^{$GLOBALS['q_config']['language']}(\/|$)/", '', $req_uri);
+            }
+            $pathinfo = trim($pathinfo, '/');
+            $pathinfo = preg_replace("|^$home_path|", '', $pathinfo);
+            $pathinfo = trim($pathinfo, '/');
+            $self = trim($self, '/');
+            $self = preg_replace("|^$home_path|", '', $self);
+            $self = trim($self, '/');
+
+            // The requested permalink is in $pathinfo for path info requests and
+            //  $req_uri for other requests.
+            if ( ! empty($pathinfo) && !preg_match('|^.*' . $wp_rewrite->index . '$|', $pathinfo) ) {
+                $request = $pathinfo;
+            } else {
+                // If the request uri is the index, blank it out so that 
+                // we don't try to match it against a rule.
+                if ( $req_uri == $wp_rewrite->index )
+                    $req_uri = '';
+                $request = $req_uri;
+            }
+            
+            $wp->request = $request;
+
+            // Look for matches.
+            $request_match = $request;
+            if ( empty( $request_match ) ) {
+                // An empty request could only match against ^$ regex
+                if ( isset( $rewrite['$'] ) ) {
+                    $wp->matched_rule = '$';
+                    $query = $rewrite['$'];
+                    $matches = array('');
+                }
+            } else if ( $req_uri != 'wp-app.php' ) {
+                foreach ( (array) $rewrite as $match => $query ) {
+                    // If the requesting file is the anchor of the match, prepend it to the path info.
+                    if ( ! empty($req_uri) && strpos($match, $req_uri) === 0 && $req_uri != $request ) {
+                        $request_match = $req_uri . '/' . $request;
+                    }
+
+                    if ( preg_match("#^$match#", $request_match, $matches) || preg_match("#^$match#", urldecode($request_match), $matches) ) {
+
+                        if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
+                            // this is a verbose page match, lets check to be sure about it
+                            if ( ! $page_foundid = $this->get_page_by_path( $matches[ $varmatch[1] ] ) ) {
+                                continue;
+                            } else {
+                                wp_cache_set('qts_page_request', $page_foundid); // caching query :)
+                            }       
+                        }
+
+                        // Got a match.
+                        $wp->matched_rule = $match;
+                        break;
+                    }
+                }
+            }
+
+            if ( isset( $wp->matched_rule ) ) {
+                // Trim the query of everything up to the '?'.
+                $query = preg_replace("!^.+\?!", '', $query);
+
+                // Substitute the substring matches into the query.
+                $query = addslashes(WP_MatchesMapRegex::apply($query, $matches));
+
+                $wp->matched_query = $query;
+
+                // Parse the query.
+                parse_str($query, $perma_query_vars);
+
+                // If we're processing a 404 request, clear the error var
+                // since we found something.
+                unset( $_GET['error'] );
+                unset( $error );
+            }
+
+            // If req_uri is empty or if it is a request for ourself, unset error.
+            if ( empty($request) || $req_uri == $self || strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) {
+                unset( $_GET['error'] );
+                unset( $error );
+
+                if ( isset($perma_query_vars) && strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) {
+                    unset( $perma_query_vars );
+                }
+
+                $wp->did_permalink = false;
+            }
+        }
+
+        return count(array_diff($query_vars, $wp->public_query_vars)) > 0 ? $query_vars : $wp->public_query_vars;
+    }
+    
+    
+    
+    /**
+     * Function called when query parameters are processed by Wordpress.
+     * 
+     * @param $query query parameters
+     * @return array() $query processed
+     *
+     * @since 1.0
+     */
+    function filter_request( $query ) {
+        global $wp_query, $wp;
+        if ((isset($wp->matched_query) || empty($query))  && ! isset($query['s']) ) {
+            $query = wp_parse_args($wp->matched_query);
+        }
+        
+        foreach (get_post_types() as $post_type) {
+            if ( array_key_exists($post_type, $query) && !in_array($post_type, array('post', 'page')) ) {
+                $query['post_type'] = $post_type;
+            }
+        }
+        
+        $page_foundit = false;
+        
+        // -> page
+        if ( isset($query['pagename']) || isset($query['page_id']) ):
+            
+            $page = wp_cache_get('qts_page_request');
+            if (!$page) 
+                $page = isset($query['page_id']) ? get_post($query['page_id']) : $this->get_page_by_path($query['pagename']);
+            
+            if (!$page) return $query;
+            $id = $page->ID;
+            $cache_array = array($page);
+            update_post_caches($cache_array, 'page'); // caching query :)
+            wp_cache_delete('qts_page_request');
+            $query['pagename'] = get_page_uri($page);
+            $function = 'get_page_link';
+        
+        // -> custom post type
+        elseif ( isset($query['post_type']) ):
+            
+            $page_slug = ( isset($query['name']) && !empty($query['name']) ) ? $query['name'] : $query[$query['post_type']];
+            $page = $this->get_page_by_path($page_slug, OBJECT, $query['post_type']);
+            if (!$page) return $query;
+            $id = $page->ID;
+            $cache_array = array($page);
+            update_post_caches($cache_array, $query['post_type']); // caching query :)
+            $query['name'] = $query[$query['post_type']] = get_page_uri($page); 
+            $function = 'get_post_permalink';
+        
+        // -> post
+        elseif ( isset($query['name']) || isset($query['p']) ):
+            
+            $post = isset($query['p']) ? get_post($query['p']) : $this->get_page_by_path($query['name'], OBJECT, 'post');
+            if (!$post) {
+                return $query;
+            }
+            $query['name'] = $post->post_name;
+            $id = $post->ID;
+            $cache_array = array($post);
+            update_post_caches($cache_array);
+            $function = 'get_permalink';
+            
+        // -> category
+        elseif ( ( isset($query['category_name']) || isset($query['cat'])) ):
+            if ( isset($query['category_name']) ) {
+                $term_slug = $this->get_last_slash( $query['category_name'] );
+            }
+            $term = isset($query['cat']) ? get_term($query['cat'], 'category') : $this->get_term_by('slug', $term_slug, 'category');
+            if (!$term) {
+                return $query;
+            }
+            $cache_array = array($term);
+            update_term_cache($cache_array, 'category'); // caching query :)
+            $id = $term->term_id;
+            $query['category_name'] = $term->slug; // uri
+            $function = 'get_category_link';
+        
+        // -> tag
+        elseif ( isset($query['tag']) ):
+            
+            $term = $this->get_term_by('slug', $query['tag'], 'post_tag');
+            if (!$term) {
+                return $query;
+            }
+            $cache_array = array($term);
+            update_term_cache($cache_array, 'post_tag'); // caching query :)
+            $id = $term->term_id;
+            $query['tag'] = $term->slug;
+            $function = 'get_tag_link';
+        
+        endif;
+
+        
+        // -> taxonomy
+        $taxonomies = get_taxonomies( array( 'public' => true, '_builtin' => false )  );
+        foreach ($taxonomies as $term_name):
+        if ( isset($query[$term_name]) ) {
+            
+            $term_slug = $this->get_last_slash( $query[$term_name] );
+            $term = $this->get_term_by('slug', $term_slug, $term_name);
+            if (!$term) {
+                return $query;
+            }
+            $cache_array = array($term);
+            update_term_cache($cache_array, $term_name); // caching query :)
+            $id = $term;
+            $query[$term_name] = $term->slug;
+            $function = 'get_term_link';
+            
+        }
+        endforeach;
+
+        // -> home url
+        if ( empty($query) ) {
+            
+            $function = 'home_url';
+            $id = '';
+            
+        }
+        
+        // -> search
+        if (isset($query['s'])) {
+
+          $id = $query['s'];
+          $function="get_search_link";
+      
+        }
+        
+        if ( isset($function) ) {
+                    
+            // parse all languages links
+            foreach( $this->get_enabled_languages() as $lang ) {
+                
+                $this->lang = $lang;
+                $this->current_url[$lang] = esc_url(apply_filters('qts_url_args', call_user_func($function, $id)));
+            }
+
+            $this->lang = false;
+        }
+        
+        return $query;
+    }
+    
+    
+    
+    /**
+     * Parse a hierarquical name and extract the last one
+     *
+     * @param string $lang Page path
+     * @return string
+     *
+     * @since 1.0
+     */
+    public function get_current_url( $lang = false ) {
+        
+        if (!$lang) {
+            $lang = $this->get_lang();
+        }
+        
+        if (isset($this->current_url[$lang]) && !empty($this->current_url[$lang])) {
+            return $this->current_url[$lang];
+        }
+        
+        return '';
+    }
+    
+    
+    
+    /**
+     * Parse a hierarquical name and extract the last one 
+     *
+     * @param string $slug Page path
+     * @return string
+     *
+     * @since 1.0
+     */
+    private function get_last_slash($slug) {
+        
+        $slug = rawurlencode( urldecode( $slug ) );
+        $slug = str_replace('%2F', '/', $slug);
+        $slug = str_replace('%20', ' ', $slug);
+        $exploded_slug = explode('/', $slug);
+
+        return array_pop( $exploded_slug );
+    }
+    
+    
+    
+    /**
+     * Retrieves a page id given its path.
+     *
+     * @param string $page_path Page path
+     * @param string $output Optional. Output type. OBJECT, ARRAY_N, or ARRAY_A. Default OBJECT.
+     * @param string $post_type Optional. Post type. Default page.
+     * @return mixed Null when complete.
+     *
+     * @since 1.0
+     */
+    private function get_page_id_by_path($page_path, $output = OBJECT, $post_type = 'page') {
+        global $wpdb;
+
+        $page_path = rawurlencode(urldecode($page_path));
+        $page_path = str_replace('%2F', '/', $page_path);
+        $page_path = str_replace('%20', ' ', $page_path);
+        $parts = explode( '/', trim( $page_path, '/' ) );
+        $parts = array_map( 'esc_sql', $parts );
+        $parts = array_map( 'sanitize_title_for_query', $parts );
+        $in_string = "'". implode( "','", $parts ) . "'";
+        $meta_key = $this->get_meta_key();
+        $post_type_sql = $post_type;
+        $wpdb->escape_by_ref( $post_type_sql );
+        
+        $pages = $wpdb->get_results( "SELECT $wpdb->posts.ID, $wpdb->posts.post_parent, $wpdb->postmeta.meta_value FROM $wpdb->posts,$wpdb->postmeta WHERE $wpdb->posts.ID = $wpdb->postmeta.post_id AND $wpdb->postmeta.meta_key = '$meta_key' AND $wpdb->postmeta.meta_value IN ($in_string) AND ($wpdb->posts.post_type = '$post_type_sql' OR $wpdb->posts.post_type = 'attachment')", OBJECT_K );
+
+        $revparts = array_reverse( $parts );
+
+        $foundid = 0;
+        foreach ( (array) $pages as $page ) {
+            if ( $page->meta_value == $revparts[0] ) {
+                $count = 0;
+                $p = $page;
+                while ( $p->post_parent != 0 && isset( $pages[ $p->post_parent ] ) ) {
+                    $count++;
+                    $parent = $pages[ $p->post_parent ];
+                    if ( ! isset( $revparts[ $count ] ) || $parent->meta_value != $revparts[ $count ] ) {
+                        break;
+                    }
+                    $p = $parent;
+                }
+
+                if ( $p->post_parent == 0 && $count+1 == count( $revparts ) && $p->meta_value == $revparts[ $count ] ) {
+                    $foundid = $page->ID;
+                    break;
+                }
+            }
+        }
+        
+        if ( $foundid ) {
+            return $foundid;
+            
+        } else {
+            
+            $last_part = array_pop($parts);
+            $page_id = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_name = '$last_part' AND (post_type = '$post_type_sql' OR post_type = 'attachment')" );
+            
+            if ( $page_id ) {
+                return $page_id;
+            }
+        }
+
+        return null;
+    }
+    
+    
+    
+    
+    /**
+     * Retrieves a page given its path.
+     *
+     * @param string $page_path Page path
+     * @param string $output Optional. Output type. OBJECT, ARRAY_N, or ARRAY_A. Default OBJECT.
+     * @param string $post_type Optional. Post type. Default page.
+     * @return mixed Null when complete.
+     *
+     * @since 1.0
+     */
+    private function get_page_by_path($page_path, $output = OBJECT, $post_type = 'page') {
+        
+        $foundid = $this->get_page_id_by_path($page_path, $output, $post_type);
+        if ( $foundid ) {
+            return get_post( $foundid, $output );
+        }
+        
+        return null;
+    }
+    
+    
+    
+    /**
+     * Ignores if the mod_rewrite func is the caller
+     *
+     * @return boolean
+     *
+     * @since 1.0
+     */
+    private function ignore_rewrite_caller() {
+        
+        $backtrace = debug_backtrace();
+        
+        $ignore_functions = array('mod_rewrite_rules', 'save_mod_rewrite_rules', 'flush_rules', 'rewrite_rules', 'wp_rewrite_rules', 'query_vars');
+        
+        if ( isset($backtrace['function']) ) {
+            if (in_array($backtrace['function'], $ignore_functions)) {
+                return true;
+            }
+        } else {
+            foreach ($backtrace as $trace) {
+                if ( isset($trace['function']) && in_array($trace['function'], $ignore_functions) ) {
+                    return true;
+                }
+            }
+        }
+        
+        return false;
+    }
+    
+    
+    /**
+     * Retrieve the home url for a given site.
+     *
+     * @param  int $blog_id   (optional) Blog ID. Defaults to current blog.
+     * @param  string $path   (optional) Path relative to the home url.
+     * @param  string $scheme (optional) Scheme to give the home url context. Currently 'http', 'https'.
+     * @return string Home url link with optional path appended.
+     *
+     * @since 1.0
+     */
+    public function home_url($url, $path, $scheme, $blog_id) {
+        if ( !in_array( $scheme, array( 'http', 'https' ) ) ) {
+            $scheme = is_ssl() && !is_admin() ? 'https' : 'http';
+        }
+
+        if ( empty( $blog_id ) || !is_multisite() ) {
+            $url = get_option( 'home' );
+        } else {
+            $url = get_blog_option( $blog_id, 'home' );
+        }
+
+        if ( 'http' != $scheme ) {
+            $url = str_replace( 'http://', "$scheme://", $url );
+        }
+
+        $ignore_caller = $this->ignore_rewrite_caller();
+
+        if ( !empty( $path ) && is_string( $path ) && strpos( $path, '..' ) === false ) {
+            $url .= '/' . ltrim( $path, '/' );
+        }
+
+        if ( !$ignore_caller ) {
+            $url = call_user_func($this->get_plugin_prefix() . 'convertURL', $url, $this->get_lang(), true);
+        }
+
+        return $url;
+    }
+    
+    
+    
+    /**
+     * Filter that changes the permastruct depending
+     * 
+     * @param string $permastruct default permastruct given b wp_rewrite
+     * @param string $name the name of the extra permastruct
+     * @return string processed permastruct
+     *
+     * @since 1.0
+     */
+    public function get_extra_permastruct( $permastruct = false, $name = false ) {
+        
+        if ( !$name || !$permastruct ) {
+            return '';
+        }
+        
+        if ( $base = $this->get_base_slug($name, $this->get_lang()) ) {
+            return "/$base/%$name%";
+        }
+        
+        return $permastruct;
+    }
+        
+    
+    
+    /**
+     * Filter that translates the slug parts in a page link
+     * 
+     * @param $link the link for the page generated by Wordpress
+     * @param $id the id of the page
+     * @return the link translated
+     *
+     * @since 1.0
+     */
+    public function post_type_link( $link, $post, $leavename, $sample ) {
+        global $wp_rewrite;
+
+        if ( is_wp_error( $post ) ) {
+            return $post;
+        }
+
+        $post_link = apply_filters( 'qts_permastruct', $wp_rewrite->get_extra_permastruct($post->post_type), $post->post_type);
+        
+        $slug = get_post_meta( $post->ID, $this->get_meta_key(), true );
+        if (!$slug) {
+            $slug =  $post->post_name;
+        }
+
+        $draft_or_pending = isset($post->post_status) && in_array( $post->post_status, array( 'draft', 'pending', 'auto-draft' ) );
+
+        $post_type = get_post_type_object($post->post_type);
+
+        if ( !empty($post_link) && ( !$draft_or_pending || $sample ) ) {
+            if ( ! $leavename ) {
+                if ( $post_type->hierarchical )
+                    $slug = $this->get_page_uri($post->ID);
+                $post_link = str_replace("%$post->post_type%", $slug, $post_link);
+            }
+            
+            $post_link = home_url( user_trailingslashit($post_link) );
+            
+        } else {
+            
+            if ( $post_type->query_var && ( isset($post->post_status) && !$draft_or_pending ) ) {
+                $post_link = add_query_arg($post_type->query_var, $slug, '');
+            } else {
+                $post_link = add_query_arg(array('post_type' => $post->post_type, 'p' => $post->ID), '');
+            }
+            
+            $post_link = home_url($post_link);
+        }
+
+        return $post_link;
+    }
+    
+    
+    
+    /**
+     * Filter that translates the slug in a post link
+     * 
+     * @param $link the link generated by wordpress
+     * @param $post the post data
+     * @param $leavename parameter used by get_permalink. Whether to keep post name or page name. 
+     * @return the link translated
+     *
+     * @since 1.0
+     */
+    public function post_link( $link, $post, $leavename ) {
+        global $q_config;
+        
+        $rewritecode = array(
+            '%year%',
+            '%monthnum%',
+            '%day%',
+            '%hour%',
+            '%minute%',
+            '%second%',
+            $leavename? '' : '%postname%',
+            '%post_id%',
+            '%category%',
+            '%author%',
+            $leavename? '' : '%pagename%',
+        );
+
+        if ( empty($post->ID) ) {
+            return false;
+        }
+
+        $permalink = $this->permalink_structure;
+
+        if ( '' != $permalink && !in_array($post->post_status, array('draft', 'pending', 'auto-draft')) ) {
+            $unixtime = strtotime($post->post_date);
+            
+            $category = '';
+            if ( strpos($permalink, '%category%') !== false ) {
+                $cats = get_the_category($post->ID);
+                if ( $cats ) {
+                    usort($cats, '_usort_terms_by_ID'); // order by ID
+                    
+                    $category = get_term_meta($cats[0]->term_id, $this->get_meta_key(), true );
+                    if (!$category) $category = $cats[0]->slug;
+                    
+                    if ( $parent = $cats[0]->parent )
+                        $category = $this->get_category_parents($parent, false, '/', true) . $category;
+                }
+                // show default category in permalinks, without
+                // having to assign it explicitly
+                if ( empty($category) ) {
+                    $default_category = get_category( get_option( 'default_category' ) );
+                    
+                    $default_category_slug = get_term_meta($default_category->term_id, $this->get_meta_key(), true );
+                    if (!$default_category_slug) $default_category_slug = $default_category->slug;
+                    
+                    $category = is_wp_error( $default_category ) ? '' : $default_category_slug;
+                }
+            }
+
+            $author = '';
+            if ( strpos($permalink, '%author%') !== false ) {
+                $authordata = get_userdata($post->post_author);
+                $author = $authordata->user_nicename;
+            }
+
+            $date = explode(" ",date('Y m d H i s', $unixtime));
+            
+            $post_slug = get_post_meta($post->ID, $this->get_meta_key(), true );
+            if (!$post_slug) {
+                $post_slug = $post->post_name;
+            }
+            
+            $rewritereplace =
+            array(
+                $date[0],
+                $date[1],
+                $date[2],
+                $date[3],
+                $date[4],
+                $date[5],
+                $post_slug,
+                $post->ID,
+                $category,
+                $author,
+                $post_slug,
+            );
+            $permalink = home_url( str_replace($rewritecode, $rewritereplace, $permalink));
+            if ($q_config['url_mode'] != 1) {
+                $permalink = user_trailingslashit($permalink, 'single');
+            }
+        } else { // if they're not using the fancy permalink option
+            $permalink = home_url('?p=' . $post->ID);
+        }
+        
+        return $permalink;
+    }
+    
+    
+    
+    /**
+     * Retrieve category parents with separator.
+     *
+     * @param int $id Category ID.
+     * @param bool $link Optional, default is false. Whether to format with link.
+     * @param string $separator Optional, default is '/'. How to separate categories.
+     * @param bool $nicename Optional, default is false. Whether to use nice name for display.
+     * @param array $visited Optional. Already linked to categories to prevent duplicates.
+     * @return string
+     *
+     * @since 1.0
+     */
+    private function get_category_parents( $id, $link = false, $separator = '/', $nicename = false, $visited = array() ) {
+        
+        $chain = '';
+        if(phpversion() >= 5.4) {
+            $parent = get_category( $id );
+        } else {
+            $parent = &get_category( $id );
+        }
+
+        if ( is_wp_error( $parent ) ) {
+            return $parent;
+        }
+
+        if ( $nicename ) {
+
+            $name = get_term_meta($parent->term_id, $this->get_meta_key(), true );
+            if (!$name) {
+                $name = $parent->slug;
+            }
+        } else {
+            $name = $parent->name;
+        }
+
+        if ( $parent->parent && ( $parent->parent != $parent->term_id ) && !in_array( $parent->parent, $visited ) ) {
+            $visited[] = $parent->parent;
+            $chain .= $this->get_category_parents( $parent->parent, $link, $separator, $nicename, $visited );
+        }
+        
+        if ( $link ) {
+            $chain .= '<a href="' . get_category_link( $parent->term_id ) . '" title="' . esc_attr( sprintf( __( "View all posts in %s", "qts" ), $parent->name ) ) . '">'.$name.'</a>' . $separator;
+        } else {
+            $chain .= $name.$separator;
+        }
+        
+        return $chain;
+    }
+    
+
+    
+    
+    
+    /**
+     * Filter that translates the slug parts in a page link
+     * 
+     * @param $link the link for the page generated by Wordpress
+     * @param $id the id of the page
+     * @return the link translated
+     *
+     * @since 1.0
+     */
+    public function _get_page_link( $link, $id ) {
+        global $post, $wp_rewrite, $q_config;
+
+        $current_post = $post;
+
+        if ( !$id ) {
+            $id = (int) $post->ID;
+        } else {
+            if(phpversion() >= 5.4) {
+                $current_post = get_post($id);
+            } else {
+                $current_post = &get_post($id);
+            }
+        }
+
+        $draft_or_pending = in_array( $current_post->post_status, array( 'draft', 'pending', 'auto-draft' ) );
+
+        $link = $wp_rewrite->get_page_permastruct();
+
+        if ( !empty($link) && ( isset($current_post->post_status) && !$draft_or_pending ) ) {
+            
+            $link = str_replace('%pagename%', $this->get_page_uri($id), $link);
+            
+            $link = trim($link, '/'); // hack
+            $link = home_url("/$link/"); // hack
+            
+            if ($q_config['url_mode'] != 1)
+                $link = user_trailingslashit($link, 'page');
+            
+        } else {
+            
+            $link = home_url("?page_id=$id");
+        }
+
+        return $link;
+    }
+    
+    
+    
+    /**
+     * Builds URI for a page.
+     *
+     * Sub pages will be in the "directory" under the parent page post name.
+     *
+     * @param mixed $page Page object or page ID.
+     * @return string Page URI.
+     *
+     * @since 1.0
+     */
+    private function get_page_uri($page) {
+        
+        if ( ! is_object($page) ) {
+            $page = get_post($page);
+        }
+        
+        $uri = get_post_meta( $page->ID, $this->get_meta_key(), true );
+        if (!$uri) {
+            $uri =  $page->post_name;
+        }
+
+        // A page cannot be it's own parent.
+        if ( $page->post_parent == $page->ID ) {
+            return $uri;
+        }
+
+        while ($page->post_parent != 0) {
+            $page = get_post($page->post_parent);
+            
+            $page_name = get_post_meta( $page->ID, $this->get_meta_key(), true );
+            if (!$page_name) {
+                $page_name = $page->post_name;
+            }
+            
+            $uri = $page_name . "/" . $uri;
+        }
+
+        return $uri;
+    }
+    
+    
+    
+    /**
+     * Filter that translates the slug parts in a term link
+     * 
+     * @param $link the link for the page generated by Wordpress
+     * @param $term object
+     * @param $taxonomy object
+     * @return the link translated
+     *
+     * @since 1.0
+     */
+    public function term_link( $link, $term, $taxonomy ) {
+        global $wp_rewrite;
+        
+        // parse normal term names for ?tag=tagname
+        if (empty($this->permalink_structure)) return $link;
+
+        if ( !is_object($term) ) {
+            if ( is_int($term) ) {
+                $term = &get_term($term, $taxonomy);
+            } else {
+                $term = $this->get_term_by('slug', $term, $taxonomy);
+            }
+        }
+
+        if ( !is_object($term) ) {
+            $term = new WP_Error('invalid_term', __('Empty Term', 'qts'));
+        }
+
+        if ( is_wp_error( $term ) ) {
+            return $term;
+        }
+
+        $taxonomy = $term->taxonomy;
+
+        $termlink = apply_filters( 'qts_permastruct', $wp_rewrite->get_extra_permastruct($taxonomy), $taxonomy);
+        
+        $slug = get_term_meta( $term->term_id, $this->get_meta_key(), true );
+        if (!$slug) {
+            $slug = $term->slug;
+        }
+        
+        $t = get_taxonomy($taxonomy);
+
+        if ( empty($termlink) ) {
+            if ( 'category' == $taxonomy )
+                $termlink = '?cat=' . $term->term_id;
+            elseif ( $t->query_var )
+                $termlink = "?$t->query_var=$slug";
+            else
+                $termlink = "?taxonomy=$taxonomy&term=$slug";
+            $termlink = home_url($termlink);
+        } else {
+            if ( $t->rewrite['hierarchical'] ) {
+                $hierarchical_slugs = array();
+                $ancestors = get_ancestors($term->term_id, $taxonomy);
+                foreach ( (array)$ancestors as $ancestor ) {
+                    $ancestor_term = get_term($ancestor, $taxonomy);
+                    
+                    $ancestor_slug = get_term_meta( $ancestor_term->term_id, $this->get_meta_key(), true );
+                    if (!$ancestor_slug) $ancestor_slug = $ancestor_term->slug;
+                    
+                    $hierarchical_slugs[] = $ancestor_slug;
+                }
+                $hierarchical_slugs = array_reverse($hierarchical_slugs);
+                $hierarchical_slugs[] = $slug;
+                $termlink = str_replace("%$taxonomy%", implode('/', $hierarchical_slugs), $termlink);
+            } else {
+                $termlink = str_replace("%$taxonomy%", $slug, $termlink);
+            }
+            $termlink = home_url( user_trailingslashit($termlink, 'category') );
+        }
+        return $termlink;
+    }
+    
+    
+    
+    /**
+     * Get all Term data from database by Term field and data.
+     *
+     * @param (string) $field Either 'slug', 'name', or 'id'
+     * @param (string|int) $value Search for this term value
+     * @param (string) $taxonomy Taxonomy Name
+     * @param (string) $output Constant OBJECT, ARRAY_A, or ARRAY_N
+     * @param (string) $filter Optional, default is raw or no WordPress defined filter will applied.
+     * @return (mixed) Term Row from database. Will return false if $taxonomy does not exist or $term was not found.
+     *
+     * @since 1.0
+     */
+    private function get_term_by($field, $value, $taxonomy, $output = OBJECT, $filter = 'raw') {
+        global $wpdb;
+        
+        $original_field = $field;
+
+        if ( ! taxonomy_exists($taxonomy) ) {
+            return false;
+        }
+
+        if ( 'slug' == $field ) {
+            $field = 'm.meta_key = \''.$this->get_meta_key().'\' AND m.meta_value';
+            $value = sanitize_title($value);
+            if ( empty($value) )
+                return false;
+        } else if ( 'name' == $field ) {
+            // Assume already escaped
+            $value = stripslashes($value);
+            $field = 't.name';
+        } else {
+            $term = get_term( (int) $value, $taxonomy, $output, $filter);
+            if ( is_wp_error( $term ) )
+                $term = false;
+            return $term;
+        }
+        
+        $term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t, $wpdb->term_taxonomy AS tt, $wpdb->termmeta AS m WHERE t.term_id = tt.term_id AND tt.term_id = m.term_id AND tt.taxonomy = %s AND $field = %s LIMIT 1", $taxonomy, $value) );
+
+        if ( !$term && 'slug' == $original_field ) {
+            $field = 't.slug';
+            $term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND $field = %s LIMIT 1", $taxonomy, $value) );
+        }
+        
+        if ( !$term ) {
+            return false;
+        }
+
+        wp_cache_add($term->term_id, $term, $taxonomy);
+
+        $term = apply_filters('get_term', $term, $taxonomy);
+        $term = apply_filters("get_$taxonomy", $term, $taxonomy);
+        $term = sanitize_term($term, $taxonomy, $filter);
+
+        if ( $output == OBJECT ) {
+            return $term;
+        } elseif ( $output == ARRAY_A ) {
+            return get_object_vars($term);
+        } elseif ( $output == ARRAY_N ) {
+            return array_values(get_object_vars($term));
+        } else {
+            return $term;
+        }
+    }
+
+
+
+    /**
+     * Fix for:
+     * - Taxonomy names in Taxonomy Manage page
+     * - 'Popular Tags' in Taxonomy (Tags) Manage page
+     * - Category filter dropdown menu in Post Manage page
+     * - Category list in Post Edit page
+     * - 'Most Used' tags list in Post Edit page (but have issues when saving)
+     * 
+     * @param (array) $terms
+     * @param (string|array) $taxonomy
+     * @since 1.2
+     */
+    function get_terms($terms, $taxonomy) {
+        
+        global $pagenow;
+        
+        
+        if ( $pagenow != 'admin-ajax.php' ) {
+            
+            $meta = get_option('qtranslate_term_name');
+            $lang = call_user_func($this->get_plugin_prefix() . 'getLanguage');
+                    
+            
+            if ( !empty( $terms ) ) {
+                foreach ($terms as $term_index => $term) {
+                    // after saving, dont do anything
+                    if( ( isset($_POST['action'] ) && $_POST['action']  == "editedtag") ||
+                     !is_object( $term ) ) {
+                        return $terms;
+                    }
+                    $termname = $term->name;
+					if( isset( $meta[$termname][$lang] ) ) {
+                        $term->name = $meta[$termname][$lang];
+                    }
+                };
+            };
+        }
+        return $terms;
+    }
+
+
+
+    /**
+     * Fix for:
+     * - Taxonomy & custom taxonomy names in Post Manage page
+     * - List of tags already added to the post in Post 
+     * - Edit page (but have issues when saving)
+     *
+     * @param (array) $terms
+     * @param (int|array) $obj_id
+     * @param (string|array) $taxonomy
+     * @param (array) $taxonomy
+     * @since 1.2
+     */ 
+    function get_object_terms($terms, $obj_id, $taxonomy, $args) {
+        
+        global $pagenow;
+        
+        // Although in post edit page the tags are translated,
+        // but when saving/updating the post Wordpress considers
+        // the translated tags as new tags. Due to this
+        // issue I limit this 'hack' to the post manage
+        // page only.
+        if ( $pagenow == 'edit.php' ) {
+            
+            // $taxonomy output seems to be wrapped
+            // in single quotes, thus remove them to
+            // make the output valid
+            $tax = str_replace("'", "", $taxonomy);
+            
+            $meta = get_option('qtranslate_term_name');
+            $lang = call_user_func($this->get_plugin_prefix() . 'getLanguage');
+            
+            if ( !empty( $terms ) ) {
+                foreach ($terms as $term) {
+                    if( isset( $meta[$term->name][$lang] ) ) {
+                        $term->name = $meta[$term->name][$lang];
+                    }
+                };
+            };
+        
+        }
+        return $terms;
+    }
+
+
+
+    /**
+     * hide quickedit slug
+     * 
+     * @since 1.0
+     */
+    public function hide_quick_edit() {
+        echo "<!-- QTS remove quick edit box -->" . PHP_EOL;
+        echo "<style type=\"text/css\" media=\"screen\">" . PHP_EOL;
+        echo "  .inline-edit-row fieldset.inline-edit-col-left .inline-edit-col *:first-child + label + label  { display: none !important }" . PHP_EOL;
+        echo "</style>" . PHP_EOL;
+    }
+    
+    
+    
+    /**
+     * Hide auttomatically the wordpress slug blog in edit posts page
+     *
+     * @since 1.0
+     */
+    public function hide_slug_box() {
+        global $pagenow;
+        
+        switch ( $pagenow ):
+            case 'edit-tags.php':
+            
+                echo "<!-- QTS remove slug box -->" . PHP_EOL;
+                echo "<script type=\"text/javascript\" charset=\"utf-8\">" . PHP_EOL;
+                echo "  jQuery(document).ready(function($){" . PHP_EOL;
+                echo "      $(\"#tag-slug\").parent().hide();" . PHP_EOL;
+                echo "      $(\".form-field td #slug\").parent().parent().hide();" . PHP_EOL;
+                echo "  });" . PHP_EOL;
+                echo "</script>" . PHP_EOL;
+                break;
+            
+            case 'post.php':
+            
+                echo "<!-- QTS remove slug box -->" . PHP_EOL;
+                echo "<style type=\"text/css\" media=\"screen\">" . PHP_EOL;
+                echo "  #edit-slug-box { display: none !important}" . PHP_EOL;
+                echo "</style>" . PHP_EOL;
+                break;
+        endswitch;
+    }
+    
+    
+        
+    /**
+     * Creates a metabox for every post, page and post type avaiable
+     *
+     * @since 1.0
+     */
+    public function add_slug_meta_box() {
+        
+        if ( function_exists( 'add_meta_box' ) ) {
+            
+            $context  = apply_filters("qts_admin_meta_box_context","side");
+            $priority = apply_filters("qts_admin_meta_box_priority","high");
+
+            add_meta_box( 'qts_sectionid', __('Slug', 'qts'), array(&$this, 'draw_meta_box'), 'post', $context, $priority);
+            add_meta_box( 'qts_sectionid', __('Slug', 'qts'), array(&$this, 'draw_meta_box'), 'page', $context, $priority);
+            
+            foreach ( get_post_types( array('_builtin' => false ) ) as $ptype )
+                add_meta_box( 'qts_sectionid', __('Slug', 'qts'), array(&$this, 'draw_meta_box'), $ptype, $context, $priority );
+        }
+    }
+    
+    
+    
+    /**
+     * Shows the fields where insert the translated slugs in the post and page edit form.
+     *
+     * @param $post (object) current post object
+     *
+     * @since 1.0
+     */
+    public function draw_meta_box( $post ) {
+        global $q_config;
+      
+        // Use nonce for verification
+        echo "<table style=\"width:100%\">" . PHP_EOL;
+        echo "<input type=\"hidden\" name=\"qts_nonce\" id=\"qts_nonce\" value=\"" . wp_create_nonce( 'qts_nonce' ) . "\" />" . PHP_EOL;
+  
+        foreach ($q_config['enabled_languages'] as $lang):
+            
+            $slug = get_post_meta( $post->ID, $this->get_meta_key($lang), true);
+            
+            $value = ( $slug ) ? htmlspecialchars( $slug , ENT_QUOTES ) : '';
+            
+            echo "<tr>" . PHP_EOL;
+            echo "<th style=\"text-align:left; width:10%; color:#555 \"><label for=\"qts_{$lang}_slug\">".__($q_config['language_name'][$lang], 'qtranslate')."</label></th>" . PHP_EOL;
+            echo "<td><input type=\"text\" id=\"qts_{$lang}_slug\" name=\"qts_{$lang}_slug\" value=\"$value\" style=\"width:90%; margin-left:10%; color:#777\" /></td>" . PHP_EOL;
+            echo "</tr>" . PHP_EOL;
+            
+        endforeach;
+        
+        echo '</table>' . PHP_EOL;
+    }
+    
+    
+    
+    /**
+     * Sanitize title as slug, if empty slug
+     * 
+     * @param $post (object) the post object
+     * @param $slug (string) the slug name
+     * @param $lang (string) the language
+     * @return the slug validated
+     *
+     * @since 1.0
+     */
+    public function validate_post_slug( $slug, $post, $lang ) { 
+            
+        $post_title = trim(call_user_func($this->get_plugin_prefix() . 'use',$lang, $_POST['post_title']));
+        $post_name = get_post_meta($post->ID, $this->get_meta_key($lang), true);
+        if (!$post_name) {
+            $post_name = $post->post_name;
+        }
+        
+        $name = ( $post_title == '' || strlen($post_title) == 0 ) ? $post_name : $post_title;
+        
+        $slug = trim($slug);
+            
+        $slug = (empty($slug)) ? sanitize_title($name) : sanitize_title($slug);
+        
+        
+        
+        return htmlspecialchars( $slug , ENT_QUOTES );
+    }
+    
+    
+    
+    /**
+     * Validates post slug against repetitions per language
+     * 
+     * @param $post (object) the post object
+     * @param $slug (string) the slug name
+     * @param $lang (string) the language
+     * @return the slug validated
+     *
+     * @since 1.0
+     */
+    public function unique_post_slug( $slug, $post, $lang ) {
+        
+        $original_status = $post->post_status;
+        
+        if ( in_array($post->post_status, array('draft', 'pending')) ) {
+            $post->post_status = 'publish';
+        }
+        
+        $slug = $this->wp_unique_post_slug( $slug, $post->ID, $post->post_status, $post->post_type, $post->post_parent, $lang );
+        
+        $post->post_status = $original_status;
+        
+        return $slug;
+    }
+    
+    
+    
+    /**
+     * Computes a unique slug for the post and language, when given the desired slug and some post details.
+     *
+     * @param string $slug the desired slug (post_name)
+     * @param integer $post_ID
+     * @param string $post_status no uniqueness checks are made if the post is still draft or pending
+     * @param string $post_type
+     * @param integer $post_parent
+     * @return string unique slug for the post, based on language meta_value (with a -1, -2, etc. suffix)
+     *
+     * @since 1.0
+     */
+    public function wp_unique_post_slug( $slug, $post_ID, $post_status, $post_type, $post_parent, $lang ) {
+        if ( in_array( $post_status, array( 'draft', 'pending', 'auto-draft' ) ) ) {
+            return $slug;
+        }
+
+        global $wpdb, $wp_rewrite;
+
+        $feeds = $wp_rewrite->feeds;
+        if ( ! is_array( $feeds ) ) {
+            $feeds = array();
+        }
+        
+        $meta_key = $this->get_meta_key($lang);
+        if ( 'attachment' == $post_type ) {
+            // Attachment slugs must be unique across all types.
+            $check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND ID != %d LIMIT 1";
+            $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_ID ) );
+
+            if ( $post_name_check || in_array( $slug, $feeds ) || apply_filters( 'wp_unique_post_slug_is_bad_attachment_slug', false, $slug ) ) {
+                $suffix = 2;
+                do {
+                    $alt_post_name = substr ($slug, 0, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
+                    $post_name_check = $wpdb->get_var( $wpdb->prepare($check_sql, $alt_post_name, $post_ID ) );
+                    $suffix++;
+                } while ( $post_name_check );
+                $slug = $alt_post_name;
+            }
+        } else {
+            // Post slugs must be unique across all posts.
+            $check_sql = "SELECT $wpdb->postmeta.meta_value FROM $wpdb->posts,$wpdb->postmeta WHERE $wpdb->posts.ID = $wpdb->postmeta.post_id AND $wpdb->postmeta.meta_key = '%s' AND $wpdb->postmeta.meta_value = '%s' AND $wpdb->posts.post_type = %s AND ID != %d LIMIT 1";
+            $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $meta_key, $slug, $post_type, $post_ID ) );
+
+            if ( $post_name_check || in_array( $slug, $feeds ) || apply_filters( 'wp_unique_post_slug_is_bad_flat_slug', false, $slug, $post_type ) ) {
+                $suffix = 2;
+                do {
+                    $alt_post_name = substr( $slug, 0, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
+                    $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $meta_key, $alt_post_name, $post_type, $post_ID ) );
+                    $suffix++;
+                } while ( $post_name_check );
+                $slug = $alt_post_name;
+            }
+        }
+
+        return $slug;
+    }
+    
+    
+    
+    
+    /**
+     * Saves the translated slug when the page is saved
+     * 
+     * @param $post_id the post id
+     * @param $post the post object
+     *
+     * @since 1.0
+     */
+    public function save_postdata( $post_id, $post ) {
+        
+        $post_type_object = get_post_type_object( $post->post_type);
+        
+        
+        if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)                       // check autosave
+        || (!isset($_POST['post_ID']) || $post_id != $_POST['post_ID']) // check revision
+        || (!wp_verify_nonce( $_POST['qts_nonce'], 'qts_nonce'))                // verify nonce
+        || (!current_user_can($post_type_object->cap->edit_post, $post_id))) {  // check permission
+            return $post_id;
+        }
+        foreach ($this->get_enabled_languages() as $lang) {
+            
+            $meta_name = $this->get_meta_key($lang);
+            $meta_value = apply_filters( 'qts_validate_post_slug', $_POST["qts_{$lang}_slug"], $post, $lang);
+            delete_post_meta($post_id, $meta_name);
+            update_post_meta($post_id, $meta_name, $meta_value);
+            
+        }
+    }
+    
+    
+    
+    /**
+     * Display multiple input fields, one per language
+     * 
+     * @param $term the term object
+     *
+     * @since 1.0
+     */
+    public function show_term_fields( $term ) {
+        global $q_config;
+        
+        // prints the fields in edit page
+        if (isset($_GET['action']) && $_GET['action'] == 'edit' ):
+  
+            echo "<table class=\"form-table\">" . PHP_EOL;
+            echo "<input type=\"hidden\" name=\"qts_nonce\" id=\"qts_nonce\" value=\"" .  wp_create_nonce( 'qts_nonce' ) . "\" />" . PHP_EOL;
+  
+            foreach( $q_config['enabled_languages'] as $lang ) {
+            
+                $slug = (is_object($term)) ? get_term_meta( $term->term_id, $this->get_meta_key($lang), true ) : '';
+            
+                $value = ( $slug ) ? htmlspecialchars( $slug , ENT_QUOTES ) : '';
+            
+                echo "<tr class=\"form-field form-required\">" . PHP_EOL;
+                echo "<th scope=\"row\" valig=\"top\"><label for=\"qts_{$lang}_slug\">".sprintf( __('Slug (%s)', 'qts'), $q_config['language_name'][$lang] )."</label></th>" . PHP_EOL;
+                echo "<td><input type=\"text\" name=\"qts_{$lang}_slug\" value=\"$value\" /></td></tr>" . PHP_EOL;
+            
+            }
+        
+            echo '</table>';
+        
+        // prints the fields in new page
+        else:
+            echo "<input type=\"hidden\" name=\"qts_nonce\" id=\"qts_nonce\" value=\"" .  wp_create_nonce( 'qts_nonce' ) . "\" />" . PHP_EOL;
+  
+            foreach( $q_config['enabled_languages'] as $lang ) {
+                
+                echo "<div class=\"form-field\">" . PHP_EOL;
+            
+                $slug = (is_object($term)) ? get_term_meta( $term->term_id, $this->get_meta_key($lang), true ) : '';
+            
+                $value = ( $slug ) ? htmlspecialchars( $slug , ENT_QUOTES ) : '';
+            
+                echo "<label for=\"qts_{$lang}_slug\">".sprintf( __('Slug (%s)', 'qts'), $q_config['language_name'][$lang] )."</label>" . PHP_EOL;
+                echo "<input type=\"text\" name=\"qts_{$lang}_slug\" value=\"$value\" aria-required=\"true\">" . PHP_EOL;
+                
+                echo '</div>';
+            
+            }
+
+        endif;
+    }
+    
+    
+    
+    /**
+     * Sanitize title as slug, if empty slug
+     * 
+     * @param $term (object) the term object
+     * @param $slug (string) the slug name
+     * @param $lang (string) the language
+     * @return the slug validated
+     *
+     * @since 1.0
+     */
+    public function validate_term_slug( $slug, $term, $lang ) {
+
+        global $q_config;
+        
+        $lang_name = $q_config['term_name'][$term->name][$lang];
+        
+        $ajax_name = 'new' . $term->taxonomy;
+        
+        $post_name = isset($_POST['name']) ? $_POST['name'] : '';
+        
+        $term_name = isset($_POST[$ajax_name]) ? trim($_POST[$ajax_name]) : $post_name;
+    
+        if (empty($term_name)) {
+            return $slug;
+        }
+        
+        $name = ( $lang_name == '' || strlen($lang_name) == 0 ) ? $term_name : $lang_name;
+        
+        $slug = trim($slug);
+            
+        $slug = (empty($slug)) ? sanitize_title($name) : sanitize_title($slug);
+        
+        return htmlspecialchars( $slug , ENT_QUOTES );
+    }
+    
+    
+    
+    /**
+     * Will make slug unique per language, if it isn't already.
+     *
+     * @param string $slug The string that will be tried for a unique slug
+     * @param object $term The term object that the $slug will belong too
+     * @param object $lang The language reference 
+     * @return string Will return a true unique slug.
+     *
+     * @since 1.0
+     */
+    public function unique_term_slug($slug, $term, $lang) {
+      
+        global $wpdb;
+		
+        $meta_key_name = $this->get_meta_key($lang);
+        $query = $wpdb->prepare("SELECT term_id FROM $wpdb->termmeta WHERE meta_key = '%s' AND meta_value = '%s' AND term_id != %d ", $meta_key_name, $slug, $term->term_id);
+        $exists_slug = $wpdb->get_results($query);
+
+        if ( empty($exists_slug) ) {
+            return $slug;
+        }
+        
+        // If we didn't get a unique slug, try appending a number to make it unique.
+        $query = $wpdb->prepare("SELECT meta_value FROM $wpdb->termmeta WHERE meta_key = '%s' AND meta_value = '%s' AND term_id != %d", $meta_key_name, $slug, $term->term_id);
+
+        if ( $wpdb->get_var( $query ) ) {
+          $num = 2;
+          do {
+            $alt_slug = $slug . "-$num";
+            $num++;
+            $slug_check = $wpdb->get_var(
+              $wpdb->prepare(
+               "SELECT meta_value FROM $wpdb->termmeta WHERE meta_key = '%s' AND meta_value = '%s'",
+               $meta_key_name,
+               $alt_slug) );
+          } while ( $slug_check );
+          $slug = $alt_slug;
+        }
+
+        return $slug;
+    }
+    
+    
+    
+    /**
+     * Display multiple input fields, one per language
+     * 
+     * @param $term_id the term id
+     * @param $tt_id the term taxonomy id
+     * @param $taxonomy the term object
+     *
+     * @since 1.0
+     */
+    public function save_term( $term_id, $tt_id, $taxonomy ) {
+        
+        $cur_screen = get_current_screen();
+        if ( (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE )  // check autosave
+        || ( !current_user_can('edit_posts') ) // check permission
+        || ( isset($cur_screen) && $cur_screen->id === "nav-menus") 
+        ) {                  
+            return $term_id;
+        }
+        
+        $term = get_term( $term_id, $taxonomy);
+        foreach( $this->get_enabled_languages() as $lang ) {
+            $meta_name = $this->get_meta_key($lang);
+      
+            //43LC: when at the post edit screen and creating a new tag
+            // the $slug comes from $_POST with the value of the post slug,
+            // not with the term slug. 
+            if ($_POST['action'] == "editpost")  {
+                // so we use the slug wp gave it
+                $term_slug = $term->slug;
+            } else {
+                // otherwise, its the edit term screen
+                $term_slug =  $_POST["qts_{$lang}_slug"];
+            }
+            
+            $meta_value = apply_filters( 'qts_validate_term_slug', $term_slug, $term, $lang);
+                
+            delete_term_meta($term_id, $meta_name);
+            update_term_meta($term_id, $meta_name, $meta_value);
+       }
+    }
+    
+    
+    
+    /**
+     * deletes termmeta rows associated with the term
+     * 
+     * @since 1.0
+     */ 
+    public function delete_term($term_id, $tt_id, $taxonomy) {
+        global $wpdb;
+        
+        $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->termmeta WHERE term_id = %d", $term_id ) );
+    }
+    
+    
+    
+    /**
+	 * creates and prints the forms and hides the default fields 
+	 * @param object $term the term object 
+	 * @since 1.1.12
+	 * 
+	 * TODO: merge with our own form.
+	 * TODO: move code into js file
+	 *
+	 */
+	public function qts_modify_term_form($term) {
+		echo "<script type=\"text/javascript\">\n// <![CDATA[\r\n";
+		if(is_object($term)&&isset($term->name)) {
+			$termname = $term->name;
+		} else {
+			$termname = "";
+		}
+	    if(isset($_GET['action']) && $_GET['action']=='edit') {
+		   foreach($this->get_enabled_languages() as $language) {
+			   echo $this->qts_insert_term_input('name', __('Name','qts'), $termname, $language,"edit");
+	        }
+	    } else {
+		   foreach($this->get_enabled_languages() as $language) {
+	           echo $this->qts_insert_term_input('tag-name', __('Name','qts'), $termname, $language,"new");   
+	        }
+	    }
+		// hide real category text
+		echo "if (ins != null) ins.style.display='none';\n";
+		echo "// ]]>\n</script>\n";
+	}
+
+	/**
+	 * Helper for qts_modify_term_form_for
+	 * @param string $id the term id
+	 * @param object #term the term
+	 * @param string $language the term name
+	 * @param string $action the term name
+	 * @return string $html the new input fields
+	 * @since 1.1.12
+	 * TODO: use DocumentFragment
+	 */
+	private function qts_insert_term_input($id,$name, $language,$action){
+		global $q_config;
+		$html = "";
+		if( $action === "new") {
+		    $html ="
+	        var il = document.getElementsByTagName('input'),
+	        	 d = document.createElement('div'),
+                 l = document.createTextNode('".$name." (".$q_config['language_name'][$language].")'),
+	            ll = document.createElement('label'),
+	             i = document.createElement('input'),
+	           ins = null;
+	        for(var j = 0; j < il.length; j++) {
+	            if(il[j].id=='".$id."') {
+	                ins = il[j];
+	                break;
+	            }
+	        }
+	        i.type = 'text';
+	        i.id = i.name = ll.htmlFor ='qtrans_term_".$language."';
+	    ";
+		} elseif ( $action === "edit") {
+		    $html ="
+	        var tr = document.createElement('tr'),
+	            th = document.createElement('th'),
+	            ll = document.createElement('label'),
+	             l = document.createTextNode('".$name." (".$q_config['language_name'][$language].")'),
+	            td = document.createElement('td'),
+	             i = document.createElement('input'),
+	           ins = document.getElementById('".$id."');
+	        i.type = 'text';
+	        i.id = i.name = ll.htmlFor ='qtrans_term_".$language."';
+	    ";
+	    }
+		if(isset($q_config['term_name'][$termname][$language])) {
+  		 $html .="
+		     i.value = '".addslashes(htmlspecialchars_decode($q_config['term_name'][$termname][$language], ENT_QUOTES))."';";
+		     //43LC: applied ENT_QUOTES to both edit and new forms. 
+		} else {
+		  $html .="
+			  if (ins != null)
+				  i.value = ins.value;
+			  ";
+		}
+		
+		if($language == $this->default_language) {
+			$html .="
+				i.onchange = function() { 
+					var il = document.getElementsByTagName('input'),
+					   ins = null;
+					for(var j = 0; j < il.length; j++) {
+						if(il[j].id=='".$id."') {
+							ins = il[j];
+							break;
+						}
+					}
+					if (ins != null)
+						ins.value = document.getElementById('qtrans_term_".$language."').value;
+				};
+				";
+		}
+		if( $action === "new") {
+	        $html .="
+	        if (ins != null)
+	            ins = ins.parentNode;
+	        d.className = 'form-field form-required';
+	        ll.appendChild(l);
+	        d.appendChild(ll);
+	        d.appendChild(i);
+	        if (ins != null)
+	            ins.parentNode.insertBefore(d,ins);
+	        ";
+	    } elseif ( $action === "edit") {
+	        $html .="
+	        ins = ins.parentNode.parentNode;
+	        tr.className = 'form-field form-required';
+	        th.scope = 'row';
+	        th.vAlign = 'top';
+	        ll.appendChild(l);
+	        th.appendChild(ll);
+	        tr.appendChild(th);
+	        td.appendChild(i);
+	        tr.appendChild(td);
+	        ins.parentNode.insertBefore(tr,ins);
+	        ";
+	    }
+		return $html;	
+	}
+    /**
+     * adds support for qtranslate in taxonomies
+     *
+     * @since 1.0
+     */
+    public function taxonomies_hooks() {
+    
+        $taxonomies = $this->get_public_taxonomies();
+
+        if ($taxonomies) {
+            foreach ($taxonomies  as $taxonomy ) {
+                add_action( $taxonomy->name.'_add_form', array(&$this, 'qts_modify_term_form'));
+                add_action( $taxonomy->name.'_edit_form', array(&$this, 'qts_modify_term_form'));
+                add_action( $taxonomy->name.'_add_form',  array(&$this, 'show_term_fields'));
+                add_action( $taxonomy->name.'_edit_form_fields', array(&$this, 'show_term_fields') );
+                add_filter('manage_edit-'.$taxonomy->name.'_columns', array(&$this, 'taxonomy_columns'));
+                add_filter('manage_'.$taxonomy->name.'_custom_column', array(&$this, 'taxonomy_custom_column'), 0, 3);
+            }
+        }
+    }
+    
+    
+    
+    /*
+     * Bug fix for slug column in taxonomies
+     * 
+     * @since 1.0
+     */
+    public function taxonomy_columns($columns) {
+        unset($columns['slug']);
+        unset($columns['posts']);
+        
+        $columns['qts-slug'] = __('Slug', 'qts');
+        $columns['posts'] = __('Posts', 'qts');
+        
+        return $columns;
+    }
+    
+    
+    
+    /*
+     * Bug fix for slug column in taxonomies
+     * 
+     * @since 1.0
+     */
+    public function taxonomy_custom_column($str, $column_name, $term_id) {
+        
+        switch ($column_name) {
+            case 'qts-slug':
+                echo get_term_meta($term_id, $this->get_meta_key(), true);
+                break;
+        }
+        return false;
+    }
+    
+    
+    
+    
+    /**
+     * Bug fix for multisite blog names
+     * 
+     * @since 1.0
+     */
+    public function blog_names($blogs) {
+        
+        foreach ($blogs as $blog) {
+            $blog->blogname = __($blog->blogname);
+        }
+        
+        return $blogs;
+    }
+    
+    
+    
+    /**
+     * Initialise the Language Widget selector
+     * 
+     * @since 1.0
+     */
+    public function widget_init() {
+        
+        if (class_exists('qTranslateWidget')) {
+            unregister_widget('qTranslateWidget');
+        }
+        if (class_exists('mqTranslateWidget')) {
+            unregister_widget('mqTranslateWidget');
+        }
+        if (class_exists('ppqTranslateWidget')) {
+            unregister_widget('ppqTranslateWidget');
+        }
+        
+        //if (class_exists('qTranslateXWidget')) {//it has additional features some people use.
+        //    unregister_widget('qTranslateXWidget');
+        //}
+        
+        register_widget('QtranslateSlugWidget');
+    }
+    
+    
+    
+    /**
+     * remove some default dashboard Widgets on Desktop
+     *
+     * @since 1.0
+     */
+    function remove_dashboard_widgets() {
+        global $wp_meta_boxes;
+        unset($wp_meta_boxes['dashboard']['side']['core']['dashboard_quick_press']);
+    } 
+    
+    
+    
+    /**
+     * adds support for qtranslate nav menus
+     * 
+     * @since 1.0
+     */
+    public function fix_nav_menu() {
+        global $pagenow;
+        
+        if( $pagenow != 'nav-menus.php' ) {
+            return;
+        }
+				//FIXME: fix the nav menu box
+				//        wp_enqueue_script( 'nav-menu-query',  plugins_url( 'assets/js/qts-nav-menu-min.js' , dirname(__FILE__ ) ), 'nav-menu', '1.0' );
+				//        add_meta_box( 'qt-languages', __('Languages', 'qts'), array(&$this, 'nav_menu_meta_box'), 'nav-menus', 'side', 'default' );
+    }
+    
+    
+    
+    /**
+     * draws meta box for select language
+     * 
+     * @since 1.0
+     */
+    public function nav_menu_meta_box() {
+        global $q_config;
+        echo '<p>';
+        foreach($q_config['enabled_languages'] as $id => $language) {
+            $checked = ($language == $q_config['language']) ? ' checked="checked"' : '';
+            echo '<p style="margin:0 0 5px 0"><input type="radio" style="margin-right:5px" name="wa_qt_lang" value="' . $language . '" id="wa_gt_lang_' . $id . '" ' . $checked . '/>';
+            echo '<label for="wa_gt_lang_' . $id . '">';
+            echo '<img src="' . trailingslashit(WP_CONTENT_URL).$q_config['flag_location'].$q_config['flag'][$language] . '"/>&nbsp;';
+            echo __($q_config['language_name'][$language], 'qtranslate');
+            echo '</label></p>';
+        }
+         echo '<p style="margin:0 0 5px 0"><input type="radio" style="margin-right:5px" name="wa_qt_lang" value="all" id="wa_gt_lang_999" />';
+            echo '<label for="wa_gt_lang_999">';
+            echo __('All languages', 'qts');
+            echo '</label></p>';
+        echo '</p>';
+    }
+    
+    
+    
+    /**
+     * Language select function for templating
+     *
+     * @param $type (string) choose the type of menu: 'text', 'image', 'both', 'dropdown' 
+     * @param $args (array) some args for draw the menu: array( 'id', 'class', 'short' );
+     * 
+     * @since 1.0
+     */
+    public function language_menu( $type = "text", $args = array() ) {
+        global $q_config;
+        
+
+        // default arguments
+        $defaults = array(
+            'id' => "qts-lang-menu",
+            'class' => "qts-lang-menu",
+            'short' => false
+        );
+        $args = wp_parse_args( $args, $defaults );
+        
+        $languages = call_user_func($this->get_plugin_prefix() . 'getSortedLanguages');
+        
+        // every type
+        switch ( $type ) {
+            
+            case 'image':
+            case 'text':
+            case 'both':
+            
+                $baseurl = dirname(plugins_url());
+                $num_languages = count($languages);
+                echo "<ul id=\"{$args['id']}\" class=\"qts_type_{$type} {$args['class']}\">". PHP_EOL;
+                
+                foreach( $languages as $index => $lang ):
+                    
+                    $url = $this->get_current_url($lang);
+                    // 43LC: hack to play nice with qtranslate-x
+                    if( "qtranxf_" === $this->plugin_prefix && $this->default_language === $lang ) {
+
+                        $url = qtranxf_convertURL('',$lang,false,true);
+                    }
+                    $item_class = array();
+                    if ( (string)$q_config['language'] == (string)$lang ) $item_class[] = 'current-menu-item';
+                    if ( $index == ( $num_languages - 1) ) $item_class[] = 'last-child';
+                    
+          
+                    $item_class = ' class="qts_lang_item ' . implode(' ', $item_class) . '"';
+                    
+                    $language_name = ($args['short']) ? $lang : $q_config['language_name'][$lang];
+                    
+                    if ( $type == 'image' ) {
+                        $link_class = " class=\"qtrans_flag qtrans_flag_$lang\"";
+                        $link_content = "<span style=\"display:none\">$language_name</span>";
+                    } else if ( $type == 'both' ) {
+                        $link_class = " class=\"qts_both qtrans_flag qtrans_flag_$lang\"";
+                        $link_content = "$language_name";                        
+                    } else {
+                        $link_class = '';
+                        $link_content = $language_name;
+                        $link_flag ='';
+                    }
+                    if( $type == 'image' || $type == 'both' ) {
+                        $link_flag_url =  $baseurl . '/'.$q_config['flag_location'].$q_config['flag'][$lang];
+                        
+                        //TODO: add i18n for alt attribute
+                        //43LC: hardcoding height and width
+                        $link_flag = "<img widht=\"18\" height=\"12\" src=\"$link_flag_url\" alt=\"$language_name\" />";
+                    }
+
+                    echo "<li $item_class><a href=\"$url\" lang=\"$lang\" hreflang=\"$lang\"$link_class>$link_flag$link_content</a></li>" . PHP_EOL;
+                    
+                endforeach;
+                
+                echo "</ul>". PHP_EOL;
+                
+                break;
+                
+            case 'dropdown':
+            
+                echo "<select id=\"{$args['id']}\" class=\"{$args['class']}\" onchange=\"window.location.href=this.options[this.selectedIndex].value\">". PHP_EOL;
+                
+                foreach( $languages as $index => $lang ):
+                    
+                    $url = $this->get_current_url($lang);
+                    
+                    $item_class = '';
+                    if ( (string)$q_config['language'] == (string)$lang ) $item_class = 'selected="selected"';
+                    
+                    $language_name = ($args['short']) ? $lang : $q_config['language_name'][$lang];
+                    
+                    echo "<option value=\"$url\" $item_class>$language_name</option>" . PHP_EOL;
+                    
+                endforeach;
+                
+                echo "</select>". PHP_EOL;
+
+                break;
+        }
+        
+    }
+}
diff --git a/includes/qtranslate-slug-settings-options.php b/includes/qtranslate-slug-settings-options.php
new file mode 100644
index 0000000..7a33c1e
--- /dev/null
+++ b/includes/qtranslate-slug-settings-options.php
@@ -0,0 +1,179 @@
+<?php
+/**
+ * Define our settings sections
+ *
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0
+ * 
+ * @return array key=$id, array value=$title in: add_settings_section( $id, $title, $callback, $page );
+ */
+function qts_options_page_sections() {
+	
+	$sections = array();
+	$sections['post_types'] = __('Post types', 'qts');
+	$sections['taxonomies'] = __('Taxonomies', 'qts');
+	$sections['styles']     = __('Styles', 'qts');
+	
+	return $sections;	
+}
+
+
+
+/**
+ * Helper for create arrays of choices
+ *
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0
+ *
+ * @return array
+ */
+function get_multi_txt_choices($name = false) {
+	global $q_config;
+	
+	if (!$name) return array();
+	
+	$choices = array();
+	foreach( $q_config['enabled_languages'] as $key => $lang) {
+		$label = sprintf( __('Slug (%s)', 'qts'), $q_config['language_name'][$lang] );
+		$choices[] =  "$label|$lang"; // prints: 'Slug (English)|en' ( $name = books )
+	}
+	
+	return $choices;
+}
+
+
+
+/**
+ * Define our form fields (settings) for displaying the default styles
+ *
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.1.7
+ *
+ * @return array
+ */
+function qts_options_page_styles() {
+  
+	  
+    $options[] = array(
+	    "section" => "styles",
+	    "id"      => QTS_PREFIX . "styles",
+	    "title"   => __('Change styles type', 'qts'),
+	    "desc"    => array(
+	    	__("adds a file (qts-default.css) to the theme's header.", "qts"),
+	    	__("adds a minified ( slighlty faster) file (qts-default.min.css) to the theme's header.", "qts"),
+	    	__("prints the styles directly into the theme's header.", "qts"),
+	    	__("neither include not print the default style.", "qts")
+	    	),
+	    "type"    => "multi-radio",
+	    'class'   => 'qts-style',
+	    "choices" => array(
+	    	__("file", "qts"),
+	    	__("minified", "qts"),
+	    	__("inline", "qts"),
+	    	__("none", "qts")
+	    	),
+	    "std"     => "file"
+  	);
+  
+	return $options;  
+}
+
+
+
+/**
+ * Define our form fields (settings) 
+ *
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0
+ *
+ * @return array
+ */
+function qts_options_page_fields() {
+	
+	$post_types = get_post_types( array('_builtin' => false, 'public' => true ), 'objects');
+	
+	// each post type
+	foreach ($post_types as $post_type):
+		
+		$options[] = array(
+			"section" => "post_types",
+			"id"      => QTS_PREFIX . "post_type_" . $post_type->name,
+			"title"   => $post_type->labels->singular_name,
+			"desc"    => sprintf( __( '<code>http://example.org/<u>%s</u>/some-%s/</code>', 'qts' ), $post_type->name, $post_type->name),
+			'class'	  => 'qts-slug',
+			"type"    => "multi-text",
+			"choices" => get_multi_txt_choices( $post_type->name),
+			"std"     => ""
+		);
+		
+	endforeach;
+	// end each post type
+	
+	$options[] = array(
+		"section" => "taxonomies",
+		"id"      => QTS_PREFIX . "taxonomy_category",
+		"title"   => __( 'Categories', 'qts' ),
+		"desc"    => __( '<code>http://example.org/<u>category</u>/some-category/</code>', 'qts' ),
+		"type"    => "multi-text",
+		'class'	  => 'qts-slug',
+		"choices" => get_multi_txt_choices('category'),
+		"std"     => ""
+	);
+	
+	$options[] = array(
+		"section" => "taxonomies",
+		"id"      => QTS_PREFIX . "taxonomy_post_tag",
+		"title"   => __( 'Tags', 'qts' ),
+		"desc"    => __( '<code>http://example.org/<u>tag</u>/some-tag/</code>', 'qts' ),
+		"type"    => "multi-text",
+		'class'	  => 'qts-slug',
+		"choices" => get_multi_txt_choices('post_tag'),
+		"std"     => ""
+	);
+	
+
+	$taxonomies = get_taxonomies( array( 'public' => true, 'show_ui' => true, '_builtin' => false ), 'object' ); 
+	
+	// each extra taxonomy
+	foreach ($taxonomies as $taxonomy):
+		
+		$options[] = array(
+			"section" => "taxonomies",
+			"id"      => QTS_PREFIX . "taxonomy_" . $taxonomy->name,
+			"title"   => $taxonomy->labels->singular_name,
+			"desc"    => sprintf( __( '<code>http://example.org/<u>%s</u>/some-%s/</code>', 'qts' ), $taxonomy->name, $taxonomy->name ),
+			"type"    => "multi-text",
+			'class'	  => 'qts-slug',
+			"choices" => get_multi_txt_choices( $taxonomy->name),
+			"std"     => ""
+		);
+		
+	endforeach;
+	// end each extra taxonomy
+	
+	
+	return $options;	
+}
+
+
+
+/**
+ * Contextual Help
+ *
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0
+ *
+ */
+function qts_options_page_contextual_help() {
+	
+	
+	$text 	= "<h3>" . __('Qtranslate Settings - Contextual Help','qts') . "</h3>";
+	$text 	.= "<p>" . __('Contextual help goes here. You may want to use different html elements to format your text as you want.','qts') . "</p>";
+	
+	return $text;
+}
\ No newline at end of file
diff --git a/includes/qtranslate-slug-settings.php b/includes/qtranslate-slug-settings.php
new file mode 100644
index 0000000..c52ec54
--- /dev/null
+++ b/includes/qtranslate-slug-settings.php
@@ -0,0 +1,979 @@
+<?php
+
+// page settings sections & fields as well as the contextual help text.
+include_once('qtranslate-slug-settings-options.php');
+
+
+/**
+ * Prints upgrade form in Qtranslate Slug admin page
+ *
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0
+ *
+ * @return array
+ */
+function qts_upgrade() {
+	global $qtranslate_slug;
+	
+	if ( !$qtranslate_slug->check_old_data() ) return;
+	
+	echo "<div id=\"qts-upgrade-box\" class=\"updated\" style=\"margin: 15px 0; margin-bottom:25px; padding: 10px\">" . PHP_EOL;
+	
+	echo "<h3>" . __('Upgrade your data', 'qts') . "</h3>" . PHP_EOL;
+	echo "<p>" . __('There are slugs stored with old data system. Please upgrade your data pressing upgrade button:', 'qts') . "</p>" . PHP_EOL;
+	
+	echo "<div id=\"qts-upgrade-form\">" . PHP_EOL;
+	echo "<input type=\"hidden\" id=\"qts-upgrade-action\" name=\"qts-upgrade-action\" value=\"qts-upgrade-check\" />" .PHP_EOL;
+	echo "<input type=\"hidden\" id=\"qts-upgrade-nonce\" name=\"qts-upgrade-nonce\" value=\"". wp_create_nonce('qts-upgrade') . "\" />" .PHP_EOL;
+	echo "<p><a id=\"qts-upgrade-button\" href=\"#\" class=\"button-primary\">" . __('upgrade now', 'qts') . "</a><img src=\"".admin_url('images/wpspin_light.gif')."\" class=\"qts-loading\" id=\"qts-loading\" alt=\"\"></p>" . PHP_EOL;
+	echo "</div></div>" . PHP_EOL;
+}
+
+
+/**
+ * AJAX: upgrade old database to new system
+ *
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0
+ *
+ * @return boolean
+ */
+function qts_process_old_data( $old_data = null, $type = 'post' ) {
+	global $wpdb, $qtranslate_slug;
+	
+	if ( is_null($old_data) || empty($old_data) ) return 0;
+	foreach ($old_data as $row) {
+		switch ($row->qts_type) {
+			case 1:
+			case 2:
+				update_post_meta( $row->qts_id, $qtranslate_slug->get_meta_key($row->qts_lang), $row->qts_slug);
+				break;
+			case 3:
+			case 4:
+				update_term_meta( $row->qts_id, $qtranslate_slug->get_meta_key($row->qts_lang), $row->qts_slug);
+				break;
+			case 5:
+				if ($type == 'post')
+					update_post_meta( $row->qts_id, $qtranslate_slug->get_meta_key($row->qts_lang), $row->qts_slug);
+				
+				if ($type == 'term')
+					update_term_meta( $row->qts_id, $qtranslate_slug->get_meta_key($row->qts_lang), $row->qts_slug);
+				break;
+		};
+	}
+	$wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}qtranslate_slug");
+	
+	return 1;
+}
+
+function qts_upgrade_response($type = 0, $slug = null) {
+	switch ( $type ) {
+		default:
+		case 0:
+			$response = array(
+				'status' => 0,
+				'message' => __('Sorry, some error happened. Refresh this page and try again please.', 'qts'),
+			);
+			break;
+		   
+		case 1:
+			$response = array(
+				'status' => 1,
+				'message' => __('Congratulations, your data has been upgraded, you are up to date.', 'qts'),
+			);
+			break;
+		case 2:
+			$response = array(
+				'status' => 2,
+				'message' => sprintf(__('One step more, select what type of slug is this: <strong>%s</strong>', 'qts'), $slug),
+				'options' => array( 'post' => __('Post, Page or Custom post type', 'qts'), 'term' => __('Category, tag or custom taxonomy', 'qts') )
+			);
+			break;
+	}
+	
+	return $response;
+}
+
+
+
+/**
+ * AJAX: upgrade old database to new system
+ *
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0
+ *
+ * @return JSON object
+ */
+function qts_upgrade_check() {
+	global $qtranslate_slug;
+	
+	$old_data = $qtranslate_slug->check_old_data();
+	
+	if ( wp_verify_nonce( $_POST['nonce'], 'qts-upgrade') ):
+	
+		// if data process to save...
+		if ($old_data) {
+			
+			// if defined data type 5, process to upgrade
+			if ( isset($_POST['type']) ):
+				
+				$res =  qts_process_old_data($old_data, $_POST['type']);
+				
+				$response = qts_upgrade_response($res);
+				
+			else :
+				
+				// define wich type of data is 5
+				$array_of_5 = array();
+				foreach ( $old_data as $row )
+					if ( $row->qts_type == 5 ) $array_of_5[] = $row->qts_slug;
+				
+				if (!empty($array_of_5)) $response = qts_upgrade_response(2, implode(', ', $array_of_5));
+				
+				// if no data type 5, process to upgrade
+				if (!isset($response)) {
+					$res =  qts_process_old_data($old_data);
+					$response = qts_upgrade_response($res);
+				}
+				
+			endif;
+			
+		
+		// if not continue	
+		} else {
+	
+			$response = qts_upgrade_response();
+		
+		}
+	
+	else:
+		
+		$response = qts_upgrade_response();
+		
+	endif;
+	
+	// response output
+	header( "Content-Type: application/json" );
+	echo json_encode($response);
+	exit;
+}
+add_action('wp_ajax_qts-upgrade-check',  'qts_upgrade_check');
+
+
+
+/**
+ * Helper function for defining variables for the current page
+ *
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0
+ *
+ * @return array
+ */
+function qts_get_settings() {
+	
+	$output = array();
+	
+	// put together the output array 
+	$output['qts_option_name']		= QTS_OPTIONS_NAME; // the option name as used in the get_option() call.
+	$output['qts_page_title'] 		= __('Qtranslate Slug options', 'qts'); // the settings page title
+	$output['qts_page_sections'] 	= qts_options_page_sections(); // the settings sections
+	$output['qts_page_fields'] 		= qts_options_page_fields(); // the settings fields
+	$output['qts_page_styles'] 		= qts_options_page_styles(); // the settings for style
+	
+	
+	$output['qts_contextual_help'] = qts_options_page_contextual_help(); // the contextual help
+	
+return $output;
+}
+
+
+
+/**
+ * Helper function for registering our form field settings
+ *
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0
+ *
+ * src: http://alisothegeek.com/2011/01/wordpress-settings-api-tutorial-1/
+ * @param (array) $args The array of arguments to be used in creating the field
+ * @return function call
+ */
+function qts_create_settings_field( $args = array() ) {
+	// default array to overwrite when calling the function
+	$defaults = array(
+		'id'      => 'default_field', // the ID of the setting in our options array, and the ID of the HTML form element
+		'title'   => 'Default Field', // the label for the HTML form element
+		'desc'    => 'This is a default description.', 	// the description displayed under the HTML form element
+		'std'     => '', 							// the default value for this setting
+		'type'    => 'text', 					// the HTML form element to use
+		'section' => 'main_section',	// the section this setting belongs to must match the array key of a section in qts_options_page_sections()
+		'choices' => array(), 			// (optional): the values in radio buttons or a drop-down menu
+		'class'   => '' 						// the HTML form element class. Is used for validation purposes and may be also use for styling if needed.
+	);
+	
+	// "extract" to be able to use the array keys as variables in our function output below
+	extract( wp_parse_args( $args, $defaults ) );
+	
+	// additional arguments for use in form field output in the function qts_show_form_field!
+	$field_args = array(
+		'type'      => $type,
+		'id'        => $id,
+		'desc'      => $desc,
+		'std'       => $std,
+		'choices'   => $choices,
+		'label_for' => $id,
+		'class'     => $class
+	);
+  
+  
+
+	add_settings_field( $id, $title, 'qts_show_form_field', __FILE__, $section, $field_args );
+
+}
+
+
+
+/**
+ * Register our setting, settings sections and settings fields
+ *
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0
+ *
+ */
+function qts_register_settings(){
+	
+	// get the settings sections array
+	$settings_output = qts_get_settings();
+	$qts_option_name = $settings_output['qts_option_name'];
+	
+	//setting
+	register_setting($qts_option_name, $qts_option_name, 'qts_validate_options' );
+	
+	//sections
+	if(!empty($settings_output['qts_page_sections'])){
+		// call the "add_settings_section" for each!
+		foreach ( $settings_output['qts_page_sections'] as $id => $title ) {
+			add_settings_section( $id, $title, 'qts_section_fn', __FILE__);
+		}
+	}
+		
+	//fields
+	if(!empty($settings_output['qts_page_fields'])){
+		// call the "add_settings_field" for each!
+		foreach ($settings_output['qts_page_fields'] as $option) {
+			qts_create_settings_field($option);
+		}
+	}
+	//style
+	if(!empty($settings_output['qts_page_styles'])){
+		// call the "add_settings_field" for each
+		foreach ($settings_output['qts_page_styles'] as $styleoption) {
+			qts_create_settings_field($styleoption);
+		}
+	}
+}
+add_action( 'admin_init', 'qts_register_settings' );
+
+
+
+/**
+ * Group scripts (js & css)
+ *
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0
+ *
+ */
+function qts_settings_scripts() {
+	global $qtranslate_slug;
+	
+	wp_enqueue_style('qts_theme_settings_css', plugins_url( 'assets/css/qts-settings.css' , dirname(__FILE__)  ) );
+	wp_enqueue_script( 'qts_theme_settings_js', plugins_url( 'assets/js/qts-settings.js' , dirname(__FILE__)  ), array('jquery'));
+	
+	if ($qtranslate_slug->check_old_data()) {
+		wp_enqueue_script('qts_theme_settings_upgrade_js', plugins_url( 'assets/js/qts-settings-upgrade.js' , dirname(__FILE__) ), array('jquery') );
+	}
+}
+
+
+
+/**
+ * The Admin menu page
+ *
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0
+ *
+ */
+function qts_add_menu() {
+	global $current_screen;
+
+	$settings_output = qts_get_settings();
+	// collect our contextual help text
+	$qts_contextual_help = $settings_output['qts_contextual_help'];
+	
+	// Display Settings Page link under the "Appearance" Admin Menu
+	$qts_settings_page = add_options_page(__('Qtranslate Slug options', 'qts'), __('Slug options', 'qts'), 'manage_options', QTS_PAGE_BASENAME, 'qts_show_settings_page');
+		// contextual help
+		/*
+		if ($qts_settings_page) {
+			$current_screen = get_current_screen();
+			//$current_screen->add_help_tab( array( $qts_settings_page, $qts_contextual_help ));
+		}
+		*/
+		// css & js
+		add_action( 'load-'. $qts_settings_page, 'qts_settings_scripts' );	
+}
+add_action( 'admin_menu', 'qts_add_menu' );
+
+
+
+////////////////////////////////////////////////////////////////////////////////////////
+	
+// Callback functions
+
+
+
+/**
+ * Section HTML, displayed before the first option
+ *
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0
+ *
+ * @return echoes output
+ */
+function qts_section_fn($page_section = false) {
+	
+	if ( !$page_section || !isset($page_section['id']) ) return;
+	
+	switch ($page_section['id']) {
+		case 'post_types':	
+		
+			echo "<p>" . __('For example, the post_type <kbd>books</kbd>, in Spanish would be displayed as <code>http://example.org/es/libros/post-type-name/</code>. If you leave this blank will use the default option when you <a href="http://codex.wordpress.org/Function_Reference/register_post_type">registered</a> the post_type.', 'qts') . "</p>";
+			break;
+		
+		case 'taxonomies':
+			
+			echo "<p>" . __('For example, the taxonomy <kbd>category</kbd>, in Spanish would be displayed as <code>http://example.org/es/categoria/taxonomy-name/</code>. If you leave this blank will use the default option when you <a href="http://codex.wordpress.org/Function_Reference/register_taxonomy">registered</a> the taxonomy (if you previously setup a base permastruct for <u>categories</u> or <u>tags</u> in <a href="options-permalink.php">permalinks</a> page, these bases will be overwritten by the translated ones).', 'qts') . "</p>";
+			break;
+  		case 'styles':
+
+    		echo "<p>" . __('The default styles are very minimal, and you can include them or not.', 'qts') . "</p>\n";    
+    		break;
+	}
+}
+
+
+
+/**
+ * Form Fields HTML: all form field types share the same function
+ *
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0
+ *
+ * @return echoes output
+ */
+function qts_show_form_field($args = array()) {
+	global $qtranslate_slug;
+	
+	extract( $args );
+	
+	// get the settings sections array
+	$settings_output = qts_get_settings();
+	$options = $qtranslate_slug->get_options();
+	
+	// pass the standard value if the option is not yet set in the database
+	if ( !isset( $options[$id] ) && 'type' != 'checkbox' ) {
+		$options[$id] = $std;
+	}
+	
+	// additional field class. output only if the class is defined in the create_setting arguments
+	$field_class = ($class != '') ? ' ' . $class : '';
+	
+	// switch html display based on the setting type.	
+	switch ( $type ) {
+		case 'text':
+			$options[$id] = stripslashes($options[$id]);
+			$options[$id] = esc_attr( $options[$id]);
+			echo "<input class='regular-text$field_class' type='text' id='$id' name='" . QTS_OPTIONS_NAME . "[$id]' value='$options[$id]' />";
+			echo ($desc != '') ? "<br /><span class='description'>$desc</span>" : "";
+		break;
+		
+		case "multi-text":
+			foreach($choices as $item) {
+				
+				$item = explode("|",$item); // cat_name|cat_slug
+				$item[0] = esc_html__($item[0], 'qts');
+				
+				if (!empty($options[$id])) {
+					foreach ($options[$id] as $option_key => $option_val){
+						if ($item[1] == $option_key) {
+							$value = $option_val;
+						}
+					}
+				} else {
+					$value = '';
+				}
+				
+				echo "<span>$item[0]:</span> <input class='$field_class' type='text' id='$id|$item[1]' name='" . QTS_OPTIONS_NAME . "[$id|$item[1]]' value='$value' /><br/>";
+			}
+			echo ($desc != '') ? "<span class='description'>$desc</span>" : "";
+		break;
+		
+		case 'textarea':
+			$options[$id] = stripslashes($options[$id]);
+			$options[$id] = esc_html( $options[$id]);
+			echo "<textarea class='textarea$field_class' type='text' id='$id' name='" . QTS_OPTIONS_NAME . "[$id]' rows='5' cols='30'>$options[$id]</textarea>";
+			echo ($desc != '') ? "<br /><span class='description'>$desc</span>" : ""; 		
+		break;
+		
+		case 'select':
+			echo "<select id='$id' class='select$field_class' name='" . QTS_OPTIONS_NAME . "[$id]'>";
+				foreach($choices as $item) {
+					$value 	= esc_attr($item, 'qts');
+					$item 	= esc_html($item, 'qts');
+					
+					$selected = ($options[$id]==$value) ? 'selected="selected"' : '';
+					echo "<option value='$value' $selected>$item</option>";
+				}
+			echo "</select>";
+			echo ($desc != '') ? "<br /><span class='description'>$desc</span>" : ""; 
+		break;
+		
+		case 'select2':
+			echo "<select id='$id' class='select$field_class' name='" . QTS_OPTIONS_NAME . "[$id]'>";
+			foreach($choices as $item) {
+				
+				$item = explode("|",$item);
+				$item[0] = esc_html($item[0], 'qts');
+				
+				$selected = ($options[$id]==$item[1]) ? 'selected="selected"' : '';
+				echo "<option value='$item[1]' $selected>$item[0]</option>";
+			}
+			echo "</select>";
+			echo ($desc != '') ? "<br /><span class='description'>$desc</span>" : "";
+		break;
+		
+		case 'checkbox':
+			echo "<input class='checkbox$field_class' type='checkbox' id='$id' name='" . QTS_OPTIONS_NAME . "[$id]' value='1' " . checked( $options[$id], 1, false ) . " />";
+			echo ($desc != '') ? "<br /><span class='description'>$desc</span>" : "";
+		break;
+		
+		case "multi-checkbox":
+			foreach($choices as $item) {
+				
+				$item = explode("|",$item);
+				$item[0] = esc_html($item[0], 'qts');
+				
+				$checked = '';
+				
+			    if ( isset($options[$id][$item[1]]) ) {
+					if ( $options[$id][$item[1]] == 'true') {
+			   			$checked = 'checked="checked"';
+					}
+				}
+				
+				echo "<input class='checkbox$field_class' type='checkbox' id='$id|$item[1]' name='" . QTS_OPTIONS_NAME . "[$id|$item[1]]' value='1' $checked /> $item[0] <br/>";
+			}
+			echo ($desc != '') ? "<br /><span class='description'>$desc</span>" : "";
+		break;
+
+		case "multi-radio":
+			foreach($choices as $index => $item) {
+				
+				$item = explode("|",$item);
+				$item_key = (count($item) > 1) ? esc_html($item[0], 'qts') : esc_html(end($item), 'qts');
+				$item_value = (count($item) > 1) ? esc_html($item[1], 'qts') : esc_html(end($item), 'qts');
+				
+				$checked = '';
+				
+			    if ( isset($options[$id]) && $options[$id] === $item_value) {
+			   		$checked = 'checked="checked"';
+				}
+				
+				echo "<label for='$id|$item_value'><input class='radio$field_class' type='radio' id='$id|$item_value' name='" . QTS_OPTIONS_NAME . "[$id]' value='$item_value' $checked /> <strong>$item_key</strong>";
+				if (isset($desc[$index]) && !empty($desc[$index])) {
+					echo ": " . $desc[$index];
+				}
+				echo "</label>";
+			}
+			echo (!is_array($desc) && $desc != '') ? "<br /><span class='description'>$desc</span>" : "";
+		break;
+	}
+}
+
+
+
+/**
+ * Validates base slugs per 'type' (post_type | taxonomy) and 'language' 
+ * 
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0
+ *
+ */
+function qts_sanitize_bases($base_slugs = false) {
+	
+	if ( !$base_slugs || empty($base_slugs) ) return;
+	
+	$base_slugs_processed = array();
+	$base_founded = array();
+	
+	// changing array structure
+	foreach ($base_slugs as $type => $base) {
+		foreach ($base as $lang => $value) {
+			if ($value != ""):
+				$base_value = $value;
+				$count = 2;
+				while (in_array($value, $base_founded)) {
+					$value = "$base_value-$count";
+					$count++;
+				}
+				$base_founded[] = $base_slugs[$type][$lang] = $value;
+			endif;
+		}
+	}
+	
+	return $base_slugs;
+}
+
+
+
+/**
+ * Admin Settings Page HTML
+ * 
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0
+ *
+ * @return echoes output
+ */
+function qts_show_settings_page() {
+	// get the settings sections array
+	$settings_output = qts_get_settings();
+?>
+	<div class="wrap">
+		<div class="icon32" id="icon-options-general"></div>
+		<h2><?php echo $settings_output['qts_page_title']; ?></h2>
+		
+		<p><?php  _e('If you activated previously the <a href="options-permalink.php">pretty permalinks</a>, in this section you can translate the <abbr title="en inglés, Universal Resource Locator">URLs</abbr> <strong>bases</strong> for <a href="http://codex.wordpress.org/Function_Reference/register_post_type#Arguments">public</a> post_types, categories, tags and taxonomies.', 'qts'); ?> </p>
+		
+		<form action="options.php" method="post">
+			<?php 
+			// upgrade notify
+			qts_upgrade();
+			// http://codex.wordpress.org/Function_Reference/settings_fields
+			settings_fields($settings_output['qts_option_name']);
+      
+			// http://codex.wordpress.org/Function_Reference/do_settings_sections
+			do_settings_sections(__FILE__);
+			// rewrite rules
+			flush_rewrite_rules();
+			?>
+	  <?php $css_path = plugin_dir_url(dirname(__FILE__)).'/assets/css/qts-default.css';
+            $file_styles = file_get_contents($css_path);
+            
+             
+            ?>
+            <p><?php  _e('If you selected "none", copy and use these styles as you see fit:','qts'); ?> </p>
+            <textarea name="textarea" rows="10" cols="80"><?php echo $file_styles; ?></textarea>;
+			<p class="submit">
+				<input name="Submit" type="submit" class="button-primary" value="<?php esc_attr_e('Save Changes','qts'); ?>" />
+			</p>
+			
+		</form>
+	</div><!-- wrap -->
+<?php }
+
+
+
+/**
+ * Validate input
+ *
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0 
+ * 
+ * @return array
+ */
+function qts_validate_options($input) {
+	
+	// for enhanced security, create a new empty array
+	$valid_input = array();
+	
+	// collect only the values we expect and fill the new $valid_input array
+	// i.e. whitelist our option IDs
+	
+	// get the settings sections array
+	$settings_output = qts_get_settings();
+		
+    $styleoptions =  $settings_output['qts_page_styles'];
+    
+	$slugoptions = $settings_output['qts_page_fields'];
+		
+    $options = array_merge($styleoptions,$slugoptions);
+
+	// run a foreach and switch on option type
+	foreach ($options as $option):
+	
+		switch ( $option['type'] ):
+			case 'text':
+				//switch validation based on the class!
+				switch ( $option['class'] ) {
+					//for numeric 
+					case 'numeric':
+						//accept the input only when numeric!
+						$input[$option['id']] 		= trim($input[$option['id']]); // trim whitespace
+						$valid_input[$option['id']] = (is_numeric($input[$option['id']])) ? $input[$option['id']] : 'Expecting a Numeric value!';
+						
+						// register error
+						if(is_numeric($input[$option['id']]) == FALSE) {
+							add_settings_error(
+								$option['id'], // setting title
+								QTS_PREFIX . '_txt_numeric_error', // error ID
+								__('Expecting a Numeric value! Please fix.', 'qts'), // error message
+								'error' // type of message
+							);
+						}
+					break;
+					
+					//for multi-numeric values (separated by a comma)
+					case 'multinumeric':
+						//accept the input only when the numeric values are comma separated
+						$input[$option['id']] 		= trim($input[$option['id']]); // trim whitespace
+						
+						if($input[$option['id']] !=''){
+							// /^-?\d+(?:,\s?-?\d+)*$/ matches: -1 | 1 | -12,-23 | 12,23 | -123, -234 | 123, 234  | etc.
+							$valid_input[$option['id']] = (preg_match('/^-?\d+(?:,\s?-?\d+)*$/', $input[$option['id']]) == 1) ? $input[$option['id']] : __('Expecting comma separated numeric values','qts');
+						}else{
+							$valid_input[$option['id']] = $input[$option['id']];
+						}
+						
+						// register error
+						if($input[$option['id']] !='' && preg_match('/^-?\d+(?:,\s?-?\d+)*$/', $input[$option['id']]) != 1) {
+							add_settings_error(
+								$option['id'], // setting title
+								QTS_PREFIX . '_txt_multinumeric_error', // error ID
+								__('Expecting comma separated numeric values! Please fix.','qts'), // error message
+								'error' // type of message
+							);
+						}
+					break;
+					
+					//for no html
+					case 'nohtml':
+						//accept the input only after stripping out all html, extra white space etc!
+						$input[$option['id']] 		= sanitize_text_field($input[$option['id']]); // need to add slashes still before sending to the database
+						$valid_input[$option['id']] = addslashes($input[$option['id']]);
+					break;
+					
+					//for url
+					case 'url':
+						//accept the input only when the url has been sanited for database usage with esc_url_raw()
+						$input[$option['id']] 		= trim($input[$option['id']]); // trim whitespace
+						$valid_input[$option['id']] = esc_url_raw($input[$option['id']]);
+					break;
+					
+					//for email
+					case 'email':
+						//accept the input only after the email has been validated
+						$input[$option['id']] 		= trim($input[$option['id']]); // trim whitespace
+						if($input[$option['id']] != ''){
+							$valid_input[$option['id']] = (is_email($input[$option['id']])!== FALSE) ? $input[$option['id']] : __('Invalid email', 'qts');
+						}elseif($input[$option['id']] == ''){
+							$valid_input[$option['id']] = __('This setting field cannot be empty! Please enter a valid email address.', 'qts');
+						}
+						
+						// register error
+						if(is_email($input[$option['id']])== FALSE || $input[$option['id']] == '') {
+							add_settings_error(
+								$option['id'], // setting title
+								QTS_PREFIX . '_txt_email_error', // error ID
+								__('Please enter a valid email address.', 'qts'), // error message
+								'error' // type of message
+							);
+						}
+					break;
+					
+					// a "cover-all" fall-back when the class argument is not set
+					default:
+						// accept only a few inline html elements
+						$allowed_html = array(
+							'a' => array('href' => array (),'title' => array ()),
+							'b' => array(),
+							'em' => array (), 
+							'i' => array (),
+							'strong' => array()
+						);
+						// trim whitespace
+						$input[$option['id']] 		= trim($input[$option['id']]);
+						// find incorrectly nested or missing closing tags and fix markup
+						$input[$option['id']] 		= force_balance_tags($input[$option['id']]);
+						// need to add slashes still before sending to the database
+						$input[$option['id']] 		= wp_kses( $input[$option['id']], $allowed_html);
+          
+						$valid_input[$option['id']] = addslashes($input[$option['id']]); 
+					break;
+				}
+			break;
+			
+			case "multi-text":
+				// this will hold the text values as an array of 'key' => 'value'
+				unset($textarray);
+				
+				$text_values = array();
+				foreach ($option['choices'] as $k => $v ) {
+					// explode the connective
+					$pieces = explode("|", $v);
+					
+					$text_values[] = $pieces[1];
+				}
+				
+				foreach ($text_values as $v ) {		
+					
+					// Check that the option isn't empty
+					if (!empty($input[$option['id'] . '|' . $v])) {
+						// If it's not null, make sure it's sanitized, add it to an array
+						switch ($option['class']) {
+							// different sanitation actions based on the class create you own cases as you need them
+							
+							//for numeric input
+							case 'numeric':
+								//accept the input only if is numberic!
+								$input[$option['id'] . '|' . $v]= trim($input[$option['id'] . '|' . $v]); // trim whitespace
+								$input[$option['id'] . '|' . $v]= (is_numeric($input[$option['id'] . '|' . $v])) ? $input[$option['id'] . '|' . $v] : '';
+							break;
+							
+							case 'qts-slug':
+								// strip all html tags and white-space.
+								$exploded_types = explode('_', $option['id']);
+								$type_ = end($exploded_types  );
+								$input[$option['id'] . '|' . $v]= sanitize_title( sanitize_text_field( $input[$option['id'] . '|' . $v] ) );
+								$input[$option['id'] . '|' . $v]= addslashes($input[$option['id'] . '|' . $v]);
+							break;
+							
+							// a "cover-all" fall-back when the class argument is not set
+							default:
+								// strip all html tags and white-space.
+								$input[$option['id'] . '|' . $v]= sanitize_text_field($input[$option['id'] . '|' . $v]); // need to add slashes still before sending to the database
+								$input[$option['id'] . '|' . $v]= addslashes($input[$option['id'] . '|' . $v]);
+							break;
+						}
+						// pass the sanitized user input to our $textarray array
+						$textarray[$v] = $input[$option['id'] . '|' . $v];
+					
+					} else {
+						$textarray[$v] = '';
+					}
+				}
+				// pass the non-empty $textarray to our $valid_input array
+				if (!empty($textarray)) {
+					$valid_input[$option['id']] = $textarray;
+				}
+			break;
+			
+			case 'textarea':
+				//switch validation based on the class!
+				switch ( $option['class'] ) {
+					//for only inline html
+					case 'inlinehtml':
+						// accept only inline html
+						// trim whitespace
+						$input[$option['id']] 		= trim($input[$option['id']]);
+         				// find incorrectly nested or missing closing tags and fix markup
+						$input[$option['id']] 		= force_balance_tags($input[$option['id']]);
+						//wp_filter_kses expects content to be escaped!
+						$input[$option['id']] 		= addslashes($input[$option['id']]);
+          				//calls stripslashes then addslashes
+						$valid_input[$option['id']] = wp_filter_kses($input[$option['id']]);
+					break;
+					
+					//for no html
+					case 'nohtml':
+						//accept the input only after stripping out all html, extra white space etc!
+						// need to add slashes still before sending to the database
+						$input[$option['id']] 		= sanitize_text_field($input[$option['id']]); 
+						$valid_input[$option['id']] = addslashes($input[$option['id']]);
+					break;
+					
+					//for allowlinebreaks
+					case 'allowlinebreaks':
+						//accept the input only after stripping out all html, extra white space etc!
+						// need to add slashes still before sending to the database
+						$input[$option['id']] 		= wp_strip_all_tags($input[$option['id']]); 
+						$valid_input[$option['id']] = addslashes($input[$option['id']]);
+					break;
+					
+					// a "cover-all" fall-back when the class argument is not set
+					default:
+						// accept only limited html
+						//my allowed html
+						$allowed_html = array(
+							'a' 			=> array('href' => array (),'title' => array ()),
+							'b' 			=> array(),
+							'blockquote' 	=> array('cite' => array ()),
+							'br' 			=> array(),
+							'dd' 			=> array(),
+							'dl' 			=> array(),
+							'dt' 			=> array(),
+							'em' 			=> array (), 
+							'i' 			=> array (),
+							'li' 			=> array(),
+							'ol' 			=> array(),
+							'p' 			=> array(),
+							'q' 			=> array('cite' => array ()),
+							'strong' 	=> array(),
+							'ul' 			=> array(),
+							'h1' 			=> array('align' => array (),'class' => array (),'id' => array (), 'style' => array ()),
+							'h2' 			=> array('align' => array (),'class' => array (),'id' => array (), 'style' => array ()),
+							'h3' 			=> array('align' => array (),'class' => array (),'id' => array (), 'style' => array ()),
+							'h4' 			=> array('align' => array (),'class' => array (),'id' => array (), 'style' => array ()),
+							'h5' 			=> array('align' => array (),'class' => array (),'id' => array (), 'style' => array ()),
+							'h6' 			=> array('align' => array (),'class' => array (),'id' => array (), 'style' => array ())
+						);
+						
+						$input[$option['id']] 		= trim($input[$option['id']]); // trim whitespace
+						$input[$option['id']] 		= force_balance_tags($input[$option['id']]); // find incorrectly nested or missing closing tags and fix markup
+						$input[$option['id']] 		= wp_kses( $input[$option['id']], $allowed_html); // need to add slashes still before sending to the database
+						$valid_input[$option['id']] = addslashes($input[$option['id']]);							
+					break;
+				}
+			break;
+			
+			case 'select':
+				// check to see if the selected value is in our approved array of values!
+				$valid_input[$option['id']] = (in_array( $input[$option['id']], $option['choices']) ? $input[$option['id']] : '' );
+			break;
+			
+			case 'select2':
+				// process $select_values
+					$select_values = array();
+					foreach ($option['choices'] as $k => $v) {
+						// explode the connective
+						$pieces = explode("|", $v);
+						
+						$select_values[] = $pieces[1];
+					}
+				// check to see if selected value is in our approved array of values!
+				$valid_input[$option['id']] = (in_array( $input[$option['id']], $select_values) ? $input[$option['id']] : '' );
+			break;
+			
+			case 'checkbox':
+				// if it's not set, default to null!
+				if (!isset($input[$option['id']])) {
+					$input[$option['id']] = null;
+				}
+				// Our checkbox value is either 0 or 1
+				$valid_input[$option['id']] = ( $input[$option['id']] == 1 ? 1 : 0 );
+			break;
+			
+			case 'multi-checkbox':
+				unset($checkboxarray);
+				$check_values = array();
+				foreach ($option['choices'] as $k => $v ) {
+					// explode the connective
+					$pieces = explode("|", $v);
+					
+					$check_values[] = $pieces[1];
+				}
+				
+				foreach ($check_values as $v ) {		
+					
+					// Check that the option isn't null
+					if (!empty($input[$option['id'] . '|' . $v])) {
+						// If it's not null, make sure it's true, add it to an array
+						$checkboxarray[$v] = 'true';
+					}
+					else {
+						$checkboxarray[$v] = 'false';
+					}
+				}
+				// Take all the items that were checked, and set them as the main option
+				if (!empty($checkboxarray)) {
+					$valid_input[$option['id']] = $checkboxarray;
+				}
+			break;
+
+			case 'multi-radio':
+				$valid_input[$option['id']] = (empty($input) || !isset($input[$option['id']])) ? $option['std'] : $input[$option['id']];
+			break;
+			
+		endswitch;
+  
+      	if (!empty($valid_input) && $valid_input[$option['id']] === "qts-slug" ) {
+        	$valid_input = qts_sanitize_bases($valid_input);
+      	} else {
+		    $valid_input= $valid_input;
+      	}
+  
+	endforeach;    
+    
+	return $valid_input;
+}
+
+
+
+/**
+ * Helper function for creating admin messages
+ *
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0 
+ *
+ * src: http://www.wprecipes.com/how-to-show-an-urgent-message-in-the-wordpress-admin-area
+ *
+ * @param (string) $message The message to echo
+ * @param (string) $msgclass The message class
+ * @return echoes the message
+ */
+function qts_show_msg($message, $msgclass = 'info') {
+	echo "<div id='message' class='$msgclass'>$message</div>";
+}
+
+
+
+/**
+ * Callback function for displaying admin messages
+ *
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0 
+ *
+ * @return calls qts_show_msg()
+ */
+function qts_admin_msgs() {
+	global $current_screen;
+	
+	// check for our settings page - need this in conditional further down
+	$qts_settings_pg = isset($_GET['page']) ? strpos($_GET['page'], QTS_PAGE_BASENAME) : '';
+	// collect setting errors/notices: 
+	// http://codex.wordpress.org/Function_Reference/get_settings_errors
+	$set_errors = get_settings_errors(); 
+	
+	// display admin message only for the admin to see, only on our settings page
+	// and only when setting errors/notices are returned!	
+	if(current_user_can ('manage_options') && $qts_settings_pg !== false && !empty($set_errors)){
+
+		// have our settings succesfully been updated? 
+		if($set_errors[0]['code'] == 'settings_updated' && isset($_GET['settings-updated'])){
+			qts_show_msg("<p>" . $set_errors[0]['message'] . "</p>", 'updated');
+		
+		// have errors been found?
+		}else{
+			// there maybe more than one so run a foreach loop.
+			foreach($set_errors as $set_error){
+				// set the title attribute to match the error "setting title" - need this in js file
+				qts_show_msg("<p class='setting-error-message' title='" . $set_error['setting'] . "'>" . $set_error['message'] . "</p>", 'error');
+			}
+		}
+	}
+}
+add_action('admin_notices', 'qts_admin_msgs');
diff --git a/includes/termmeta-core.php b/includes/termmeta-core.php
new file mode 100644
index 0000000..a8cfac1
--- /dev/null
+++ b/includes/termmeta-core.php
@@ -0,0 +1,223 @@
+<?php
+/**
+ * Install Term meta table - setup table, store db version for future updates
+ */
+if ( !function_exists('install_term_meta_table') ):
+function install_term_meta_table() {
+	global $wpdb;
+
+	$collate = '';
+	//if($wpdb->supports_collation())//deprecated, was a reason for activation admin notice
+	if($wpdb->has_cap( 'collation' )) {
+		if(!empty($wpdb->charset)) $collate = "DEFAULT CHARACTER SET $wpdb->charset";
+		if(!empty($wpdb->collate)) $collate .= " COLLATE $wpdb->collate";
+	}
+
+	$sql = "CREATE TABLE IF NOT EXISTS ". $wpdb->prefix . "termmeta" ." (
+		`meta_id` 				bigint(20) NOT NULL AUTO_INCREMENT,
+	  	`term_id` 				bigint(20) NOT NULL DEFAULT '0',
+	  	`meta_key` 				varchar(255) NULL,
+	  	`meta_value` 			longtext NULL,
+	  	PRIMARY KEY id (`meta_id`)) $collate;";
+	$wpdb->query($sql);
+}
+endif;
+
+
+
+function simple_post_meta_define_table() {
+	global $wpdb;
+	$wpdb->termmeta = $wpdb->prefix . 'termmeta';
+}
+add_action( 'init', 'simple_post_meta_define_table' );
+
+
+
+/**
+ * Updates metadata cache for list of term IDs.
+ *
+ * Performs SQL query to retrieve the metadata for the term IDs and updates the
+ * metadata cache for the terms. Therefore, the functions, which call this
+ * function, do not need to perform SQL queries on their own.
+ *
+ * @param array $term_ids List of post IDs.
+ * @return bool|array Returns false if there is nothing to update or an array of metadata.
+ */
+if ( !function_exists('update_termmeta_cache') ):
+	function update_termmeta_cache($term_ids) {
+		return update_meta_cache('term', $term_ids);
+	}
+endif;
+
+
+
+/**
+ * Add meta data field to a term.
+ *
+ * @param int $term_id Term ID.
+ * @param string $key Metadata name.
+ * @param mixed $value Metadata value.
+ * @param bool $unique Optional, default is false. Whether the same key should not be added.
+ * @return bool False for failure. True for success.
+ */
+if ( !function_exists('add_term_meta') ):
+	function add_term_meta( $term_id, $meta_key, $meta_value, $unique = false ) {
+		return add_metadata('term', $term_id, $meta_key, $meta_value, $unique);
+	}
+endif;
+
+
+
+/**
+ * Remove metadata matching criteria from a term.
+ *
+ * You can match based on the key, or key and value. Removing based on key and
+ * value, will keep from removing duplicate metadata with the same key. It also
+ * allows removing all metadata matching key, if needed.
+ *
+ * @param int $term_id Term ID
+ * @param string $meta_key Metadata name.
+ * @param mixed $meta_value Optional. Metadata value.
+ * @return bool False for failure. True for success.
+ */
+if ( !function_exists('delete_term_meta') ):
+	function delete_term_meta( $term_id, $meta_key, $meta_value = '' ) {
+		return delete_metadata('term', $term_id, $meta_key, $meta_value);
+	}
+endif;
+
+
+
+/**
+ * Retrieve term meta field for a term.
+ *
+ * @param int $term_id Term ID.
+ * @param string $key The meta key to retrieve.
+ * @param bool $single Whether to return a single value.
+ * @return mixed Will be an array if $single is false. Will be value of meta data field if $single
+ *  is true.
+ */
+if ( !function_exists('get_term_meta') ):
+	function get_term_meta( $term_id, $key, $single = false ) {
+		return get_metadata('term', $term_id, $key, $single);
+	}
+endif;
+
+
+
+/**
+ * Update term meta field based on term ID.
+ *
+ * Use the $prev_value parameter to differentiate between meta fields with the
+ * same key and term ID.
+ *
+ * If the meta field for the term does not exist, it will be added.
+ *
+ * @param int $term_id Term ID.
+ * @param string $key Metadata key.
+ * @param mixed $value Metadata value.
+ * @param mixed $prev_value Optional. Previous value to check before removing.
+ * @return bool False on failure, true if success.
+ */
+if ( !function_exists('update_term_meta') ):
+	function update_term_meta( $term_id, $meta_key, $meta_value, $prev_value = '' ) {
+		return update_metadata('term', $term_id, $meta_key, $meta_value, $prev_value);
+	}
+endif;
+
+
+
+/**
+ * Delete everything from term meta matching meta key.
+ *
+ * @param string $term_meta_key Key to search for when deleting.
+ * @return bool Whether the term meta key was deleted from the database
+ */
+if ( !function_exists('delete_term_meta_by_key') ):
+	function delete_term_meta_by_key($term_meta_key) {
+		if ( !$term_meta_key )
+			return false;
+
+		global $wpdb;
+		$term_ids = $wpdb->get_col($wpdb->prepare("SELECT DISTINCT term_id FROM $wpdb->termmeta WHERE meta_key = %s", $term_meta_key));
+		if ( $term_ids ) {
+			$termmetaids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->termmeta WHERE meta_key = %s", $term_meta_key ) );
+			$in = implode( ',', array_fill(1, count($termmetaids), '%d'));
+			do_action( 'delete_termmeta', $termmetaids );
+			$wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->termmeta WHERE meta_id IN($in)", $termmetaids ));
+			do_action( 'deleted_termmeta', $termmetaids );
+			foreach ( $term_ids as $term_id )
+				wp_cache_delete($term_id, 'term_meta');
+			return true;
+		}
+		return false;
+	}
+endif;
+
+
+
+/**
+ * Retrieve term meta fields, based on term ID.
+ *
+ * The term meta fields are retrieved from the cache, so the function is
+ * optimized to be called more than once. It also applies to the functions, that
+ * use this function.
+ *
+ * @param int $term_id term ID
+ * @return array
+ */
+if ( !function_exists('add_term_meta') ):
+	function get_term_custom( $term_id ) {
+		$term_id = (int) $term_id;
+
+		if ( ! wp_cache_get($term_id, 'term_meta') )
+			update_termmeta_cache($term_id);
+
+		return wp_cache_get($term_id, 'term_meta');
+	}
+endif;
+
+
+
+/**
+ * Retrieve meta field names for a term.
+ *
+ * If there are no meta fields, then nothing (null) will be returned.
+ *
+ * @param int $term_id term ID
+ * @return array|null Either array of the keys, or null if keys could not be retrieved.
+ */
+if ( !function_exists('get_term_custom_keys') ):
+	function get_term_custom_keys( $term_id ) {
+		$custom = get_term_custom( $term_id );
+
+		if ( !is_array($custom) )
+			return;
+
+		if ( $keys = array_keys($custom) )
+			return $keys;
+	}
+endif;
+
+
+
+/**
+ * Retrieve values for a custom term field.
+ *
+ * The parameters must not be considered optional. All of the term meta fields
+ * will be retrieved and only the meta field key values returned.
+ *
+ * @param string $key Meta field key.
+ * @param int $term_id Term ID
+ * @return array Meta field values.
+ */
+if ( !function_exists('get_term_custom_values') ):
+	function get_term_custom_values( $key = '', $term_id ) {
+		if ( !$key )
+			return null;
+
+		$custom = get_term_custom($term_id);
+
+		return isset($custom[$key]) ? $custom[$key] : null;
+	}
+endif;
\ No newline at end of file
diff --git a/languages/qts-es_ES.mo b/languages/qts-es_ES.mo
new file mode 100644
index 0000000..e702170
Binary files /dev/null and b/languages/qts-es_ES.mo differ
diff --git a/languages/qts-es_ES.po b/languages/qts-es_ES.po
new file mode 100644
index 0000000..3372765
--- /dev/null
+++ b/languages/qts-es_ES.po
@@ -0,0 +1,142 @@
+# Copyright (C) 2012 qTranslate slug
+# This file is distributed under the same license as the qTranslate slug package.
+msgid ""
+msgstr ""
+"Project-Id-Version: qTranslate slug 1.0\n"
+"Report-Msgid-Bugs-To: http://wordpress.org/tag/qtranslate-slug\n"
+"POT-Creation-Date: 2012-05-27 20:27:55+00:00\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"PO-Revision-Date: 2012-06-17 03:37+0100\n"
+"Last-Translator: Carlos Sanz <carlos.sanz@gmail.com>\n"
+"Language-Team: Carlos Sanz Garcia <carlos.sanz@gmail.com>\n"
+
+# qtranslate-slug.php
+msgid "Language selector"
+msgstr "Selector de idioma"
+
+# qtranslate-slug.php
+msgid "Title:"
+msgstr "Título:"
+
+# qtranslate-slug.php
+msgid "<p style=\"color:red\">This plugin requires qTranslate to be installed and activated.</p>"
+msgstr "<p style=\"color:red\">Este plugin necesita qTranslate instalado y activado previamente.</p>"
+
+# qtranslate-slug.php
+msgid "Slug"
+msgstr "Enlace permanente"
+
+# qtranslate-slug.php
+msgid "Show short name (en):"
+msgstr "Mostrar nombre corto (en):"
+
+# qtranslate-slug-settings-options.php
+msgid "Post types"
+msgstr "Post types"
+
+# qtranslate-slug-settings-options.php
+msgid "Taxonomies"
+msgstr "Taxonomias"
+
+# qtranslate-slug-settings-options.php
+msgid "Slug (%s)"
+msgstr "URL (%s)"
+
+# qtranslate-slug-settings-options.php
+msgid "<code>http://example.org/<u>%s</u>/some-%s/</code>"
+msgstr "<code>http://ejemplo.org/<u>%s</u>/algun-%s/</code>"
+
+# qtranslate-slug-settings-options.php
+msgid "<code>http://example.org/<u>category</u>/some-category/</code>"
+msgstr "<code>http://ejemplo.org/<u>categoria</u>/alguna-categoria/</code>"
+
+# qtranslate-slug-settings-options.php
+msgid "<code>http://example.org/<u>tag</u>/some-tag/</code>"
+msgstr "<code>http://ejemplo.org/<u>etiqueta</u>/alguna-etiqueta/</code>"
+
+# qtranslate-slug-settings.php
+msgid "Qtranslate Slug options"
+msgstr "Opciones de Qtranslate Slug"
+
+# qtranslate-slug-settings.php
+msgid "Slug options"
+msgstr "Opciones de URL"
+
+# qtranslate-slug-settings.php
+msgid "Save Changes"
+msgstr "Guardar cambios"
+
+# qtranslate-slug-settings.php
+msgid "Expecting a Numeric value! Please fix."
+msgstr "Se espera un valor numérico! Por favor, corrígelo."
+
+# qtranslate-slug-settings.php
+msgid "Expecting comma separated numeric values! Please fix."
+msgstr "Se esperan valores numéricos separados por coma! Por favor, corrígelo."
+
+# qtranslate-slug-settings.php
+msgid "Invalid email"
+msgstr "E-mail incorrecto"
+
+# qtranslate-slug-settings.php
+msgid "This setting field cannot be empty! Please enter a valid email address."
+msgstr "Este campo no puede estar vacío! Por favor introduce una dirección de e-mail válida."
+
+# qtranslate-slug-settings.php
+msgid "Please enter a valid email address."
+msgstr "Por favor introduce una dirección de e-mail válida."
+
+# qtranslate-slug-settings.php
+msgid "upgrade now"
+msgstr "actualizar ahora"
+
+# qtranslate-slug.php
+msgid "Please update your old data to the new system."
+msgstr "Por favor actualiza tu antiguo sistema de datos al nuevo."
+
+# qtranslate-slug-settings.php
+msgid "Upgrade your data"
+msgstr "Actualiza tus datos"
+
+# qtranslate-slug-settings.php
+msgid "There are slugs stored with old data system. Please upgrade your data pressing upgrade button:"
+msgstr "Hay slugs almacenados en el antiguo sistema. Por favor actualiza tus datos aprentando el botón actualizar:"
+
+# qtranslate-slug-settings.php
+msgid "Sorry, some error happened. Refresh this page and try again please."
+msgstr "Lo sentimos, algún tipo de error ha ocurrido. Por favor recarga esta página y prueba otra vez."
+
+# qtranslate-slug-settings.php
+msgid "Congratulations, your data has been upgraded, you are up to date."
+msgstr "Felicidades, tus datos se han actualizado, ahora estás al día."
+
+# qtranslate-slug-settings.php
+msgid "One step more, select what type of slug is this: <strong>%s</strong>"
+msgstr "Un paso más, selecction qué tipo de slug es este: <strong>%s</strong>"
+
+# qtranslate-slug-settings.php
+msgid "Post, Page or Custom post type"
+msgstr "Entrada, Página o Custom post type"
+
+# qtranslate-slug-settings.php
+msgid "Category, tag or custom taxonomy"
+msgstr "Categoria, tag o taxonomía"
+
+# qtranslate-slug.php
+msgid "This plugin requires at least <strong>Wordpress 3.3</strong> and <strong>Qtranslate(2.5.8 or newer)</strong>"
+msgstr "Este plugin requiere al menos <strong>Wordpress 3.3</strong> y <strong>Qtranslate(2.5.8 o mayor)</strong>"
+
+# qtranslate-slug-settings.php
+msgid "If you activated previously the <a href=\"options-permalink.php\">pretty permalinks</a>, in this section you can translate the <abbr title=\"en inglés, Universal Resource Locator\">URLs</abbr> <strong>bases</strong> for <a href=\"http://codex.wordpress.org/Function_Reference/register_post_type#Arguments\">public</a> post_types, categories, tags and taxonomies."
+msgstr "Si has activado previamente los <a href=\"options-permalink.php\">enlaces permanentes</a>, en esta sección podrás traducir las <strong>bases</strong> de las <abbr title=\"en inglés, Universal Resource Locator\">URLs</abbr> para post_types, categorías, etiquetas y taxonomias <a href=\"http://codex.wordpress.org/Function_Reference/register_post_type#Arguments\">públicas</a>."
+
+# qtranslate-slug-settings.php
+msgid "For example, the post_type <kbd>books</kbd>, in Spanish would be displayed as <code>http://example.org/es/libros/post-type-name/</code>. If you leave this blank will use the default option when you <a href=\"http://codex.wordpress.org/Function_Reference/register_post_type\">registered</a> the post_type."
+msgstr "Por ejemplo, para el post_type  <kbd>books</kbd> en Español se mostraría como <code>http://example.org/es/libros/post-type-name/</code>. Si dejas esto en blanco se usará la opción predeterminada cuando <a href=\"http://codex.wordpress.org/Function_Reference/register_post_type\">registraste</a> el post_type."
+
+# qtranslate-slug-settings.php
+msgid "For example, the taxonomy <kbd>category</kbd>, in Spanish would be displayed as <code>http://example.org/es/categoria/taxonomy-name/</code>. If you leave this blank will use the default option when you <a href=\"http://codex.wordpress.org/Function_Reference/register_taxonomy\">registered</a> the taxonomy (if you previously setup a base permastruct for <u>categories</u> or <u>tags</u> in <a href=\"options-permalink.php\">permalinks</a> page, these bases will be overwritten by the translated ones)."
+msgstr "Por ejemplo, la taxonomia <kbd>category</kbd>, en Español se mostraría como <code>http://example.org/es/categoria/taxonomy-name/</code>.  Si dejas esto en blanco se usará la opción predeterminada cuando <a href=\"http://codex.wordpress.org/Function_Reference/register_taxonomy\">registraste</a> la texonomia (si previamente configuraste la base de las estructuraas de <u>categorías</u> o <u>tags</u> en la página <a href=\"options-permalink.php\">enlaces permanentes</a>, estas bases serán reemplazadas por las traducidas)."
+
diff --git a/languages/qts-pt_PT.mo b/languages/qts-pt_PT.mo
new file mode 100644
index 0000000..64c0c00
Binary files /dev/null and b/languages/qts-pt_PT.mo differ
diff --git a/languages/qts-pt_PT.po b/languages/qts-pt_PT.po
new file mode 100644
index 0000000..246d426
--- /dev/null
+++ b/languages/qts-pt_PT.po
@@ -0,0 +1,343 @@
+# Copyright (C) 2012 qTranslate slug
+# This file is distributed under the same license as the qTranslate slug package.
+msgid ""
+msgstr ""
+"Project-Id-Version: qTranslate slug\n"
+"Report-Msgid-Bugs-To: http://wordpress.org/tag/qtranslate-slug\n"
+"POT-Creation-Date: 2015-01-23 14:23-0000\n"
+"PO-Revision-Date: 2015-01-23 15:26-0000\n"
+"Last-Translator: Pedro Mendonça <ped.gaspar@gmail.com>\n"
+"Language-Team: Pedro Mendonça <ped.gaspar@gmail.com>\n"
+"Language: pt_PT\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.7.3\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-SourceCharset: UTF-8\n"
+"X-Poedit-KeywordsList: __;_e;__ngettext;_n;__ngettext_noop;_n_noop;_x;_nx;"
+"_nx_noop;_ex;esc_attr__;esc_attr_e;esc_attr_x;esc_html__;esc_html_e;esc_html_x;"
+"_c;_nc\n"
+"X-Poedit-Basepath: .\n"
+"X-Poedit-SearchPath-0: .\n"
+"X-Poedit-SearchPath-1: ..\n"
+
+#: ../includes/class-qtranslate-slug-widget.php:11
+msgid "Allows your visitors to choose a Language."
+msgstr "Permite aos visitantes escolher o seu Idioma."
+
+#: ../includes/class-qtranslate-slug-widget.php:12
+msgid "Language selector"
+msgstr "Selector de idioma"
+
+#: ../includes/class-qtranslate-slug-widget.php:19
+msgid "Language"
+msgstr "Idioma"
+
+#: ../includes/class-qtranslate-slug-widget.php:51
+msgid "Title:"
+msgstr "Título:"
+
+#: ../includes/class-qtranslate-slug-widget.php:52
+msgid "Hide Title:"
+msgstr "Esconder título:"
+
+#: ../includes/class-qtranslate-slug-widget.php:53
+msgid "Display:"
+msgstr "Mostrar:"
+
+#: ../includes/class-qtranslate-slug-widget.php:54
+msgid "Text only"
+msgstr "Apenas texto"
+
+#: ../includes/class-qtranslate-slug-widget.php:55
+msgid "Image only"
+msgstr "Apenas imagem"
+
+#: ../includes/class-qtranslate-slug-widget.php:56
+msgid "Text and Image"
+msgstr "Texto e imagem"
+
+#: ../includes/class-qtranslate-slug-widget.php:57
+msgid "Dropdown Box"
+msgstr "Caixa de selecção"
+
+#: ../includes/class-qtranslate-slug-widget.php:58
+msgid "Show short name (en):"
+msgstr "Mostrar abreviatura (pt):"
+
+#: ../includes/class-qtranslate-slug.php:413
+msgid "Please update your old data to the new system."
+msgstr "Por favor actualize os seus dados antigos para o novo sistema."
+
+#: ../includes/class-qtranslate-slug.php:413
+#: ../includes/qtranslate-slug-settings.php:29
+msgid "upgrade now"
+msgstr "actualizar agora"
+
+#: ../includes/class-qtranslate-slug.php:427
+msgid "or newer"
+msgstr "ou mais recente"
+
+#: ../includes/class-qtranslate-slug.php:432
+msgid "This plugin requires at least %s and either %s, or %s, or %s"
+msgstr "Este plugin requer no mínimo o %s e o %s, ou %s, ou %s"
+
+#: ../includes/class-qtranslate-slug.php:432
+msgid "More information about"
+msgstr "Mais informações sobre"
+
+#: ../includes/class-qtranslate-slug.php:1612
+msgid "View all posts in %s"
+msgstr "Ver todos os artigos em %s"
+
+#: ../includes/class-qtranslate-slug.php:1739
+msgid "Empty Term"
+msgstr "Termo vazio"
+
+#: ../includes/class-qtranslate-slug.php:1999
+#: ../includes/class-qtranslate-slug.php:2000
+#: ../includes/class-qtranslate-slug.php:2003
+#: ../includes/class-qtranslate-slug.php:2541
+msgid "Slug"
+msgstr "URL"
+
+#: ../includes/class-qtranslate-slug.php:2214
+#: ../includes/class-qtranslate-slug.php:2233
+#: ../includes/qtranslate-slug-settings-options.php:39
+msgid "Slug (%s)"
+msgstr "URL (%s)"
+
+#: ../includes/class-qtranslate-slug.php:2400
+#: ../includes/class-qtranslate-slug.php:2404
+msgid "Name"
+msgstr "Nome"
+
+#: ../includes/class-qtranslate-slug.php:2542
+msgid "Posts"
+msgstr "Artigos"
+
+#: ../includes/class-qtranslate-slug.php:2634
+msgid "Languages"
+msgstr "Idiomas"
+
+#: ../includes/class-qtranslate-slug.php:2657
+msgid "All languages"
+msgstr "Todos os idiomas"
+
+#: ../includes/qtranslate-slug-settings-options.php:14
+msgid "Post types"
+msgstr "Tipos de artigos"
+
+#: ../includes/qtranslate-slug-settings-options.php:15
+msgid "Taxonomies"
+msgstr "Taxonomias"
+
+#: ../includes/qtranslate-slug-settings-options.php:16
+msgid "Styles"
+msgstr "Estilos"
+
+#: ../includes/qtranslate-slug-settings-options.php:63
+msgid "Change styles type"
+msgstr "﻿Alterar o tipo de estilos"
+
+#: ../includes/qtranslate-slug-settings-options.php:65
+msgid "adds a file (qts-default.css) to the theme's header."
+msgstr "adiciona um ficheiro (qts-default.css) ao cabeçalho do tema."
+
+#: ../includes/qtranslate-slug-settings-options.php:66
+msgid ""
+"adds a minified ( slighlty faster) file (qts-default.min.css) to the theme's "
+"header."
+msgstr ""
+"adiciona um ficheiro minimizado (qts-default.min.css), ligeiramente mais "
+"rápido, ao cabeçalho do tema."
+
+#: ../includes/qtranslate-slug-settings-options.php:67
+msgid "prints the styles directly into the theme's header."
+msgstr "﻿exibe os estilos directamente no cabeçalho do tema."
+
+#: ../includes/qtranslate-slug-settings-options.php:68
+msgid "neither include not print the default style."
+msgstr "nem incluir nem exibir o estilo padrão."
+
+#: ../includes/qtranslate-slug-settings-options.php:73
+msgid "file"
+msgstr "ficheiro"
+
+#: ../includes/qtranslate-slug-settings-options.php:74
+msgid "minified"
+msgstr "minimizado"
+
+#: ../includes/qtranslate-slug-settings-options.php:75
+msgid "inline"
+msgstr "em linha"
+
+#: ../includes/qtranslate-slug-settings-options.php:76
+msgid "none"
+msgstr "nenhum"
+
+#: ../includes/qtranslate-slug-settings-options.php:106
+#: ../includes/qtranslate-slug-settings-options.php:148
+msgid "<code>http://example.org/<u>%s</u>/some-%s/</code>"
+msgstr "<code>http://exemplo.org/<u>%s</u>/qualquer-%s/</code>"
+
+#: ../includes/qtranslate-slug-settings-options.php:119
+msgid "Categories"
+msgstr "Categorias"
+
+#: ../includes/qtranslate-slug-settings-options.php:120
+msgid "<code>http://example.org/<u>category</u>/some-category/</code>"
+msgstr "<code>http://exemplo.org/<u>categoria</u>/qualquer-categoria/</code>"
+
+#: ../includes/qtranslate-slug-settings-options.php:130
+msgid "Tags"
+msgstr "Etiquetas"
+
+#: ../includes/qtranslate-slug-settings-options.php:131
+msgid "<code>http://example.org/<u>tag</u>/some-tag/</code>"
+msgstr "<code>http://exemplo.org/<u>etiqueta</u>/qualquer-etiqueta/</code>"
+
+#: ../includes/qtranslate-slug-settings-options.php:175
+msgid "Qtranslate Settings - Contextual Help"
+msgstr "Definições do Qtranslate - Ajuda contextual"
+
+#: ../includes/qtranslate-slug-settings-options.php:176
+msgid ""
+"Contextual help goes here. You may want to use different html elements to "
+"format your text as you want."
+msgstr ""
+"Isto é a ajuda contextual. Poderá utilizar diferentes elementos html para "
+"formatar o seu texto como desejar."
+
+#: ../includes/qtranslate-slug-settings.php:23
+msgid "Upgrade your data"
+msgstr "Actualize os seus dados"
+
+#: ../includes/qtranslate-slug-settings.php:24
+msgid ""
+"There are slugs stored with old data system. Please upgrade your data pressing "
+"upgrade button:"
+msgstr ""
+"Existem URLs com sistema de dados antigo. Por favor actualize os seus dados "
+"através do botão actualizar:"
+
+#: ../includes/qtranslate-slug-settings.php:77
+msgid "Sorry, some error happened. Refresh this page and try again please."
+msgstr ""
+"Lamentavelmente mas ocorreu um erro. Por favor refresque esta página e tente "
+"novamente."
+
+#: ../includes/qtranslate-slug-settings.php:84
+msgid "Congratulations, your data has been upgraded, you are up to date."
+msgstr ""
+"Parabéns, os seus dados foram actualizados e o sistema está agora actual."
+
+#: ../includes/qtranslate-slug-settings.php:90
+msgid "One step more, select what type of slug is this: <strong>%s</strong>"
+msgstr "Um passo mais, seleccione que tipo de URL é este: <strong>%s</strong>"
+
+#: ../includes/qtranslate-slug-settings.php:91
+msgid "Post, Page or Custom post type"
+msgstr "Artigo, página ou tipo de artigo personalizado"
+
+#: ../includes/qtranslate-slug-settings.php:91
+msgid "Category, tag or custom taxonomy"
+msgstr "Categoria, etiqueta ou taxonomia personalizada"
+
+#: ../includes/qtranslate-slug-settings.php:182
+#: ../includes/qtranslate-slug-settings.php:322
+msgid "Qtranslate Slug options"
+msgstr "Opções do Qtranslate Slug"
+
+#: ../includes/qtranslate-slug-settings.php:322
+msgid "Slug options"
+msgstr "Opções do URL"
+
+#: ../includes/qtranslate-slug-settings.php:359
+msgid ""
+"For example, the post_type <kbd>books</kbd>, in Spanish would be displayed as "
+"<code>http://example.org/es/libros/post-type-name/</code>. If you leave this "
+"blank will use the default option when you <a href=\"http://codex.wordpress."
+"org/Function_Reference/register_post_type\">registered</a> the post_type."
+msgstr ""
+"Por exemplo, o tipo de artigo <kbd>livros</kbd>, em português seria mostrado "
+"como <code>http://exemplo.org/pt/livros/nome-de-tipo-de-artigo/</code>. Se "
+"deixar isto em branco, será usada a opção por omissão <a href=\"http://codex."
+"wordpress.org/Function_Reference/register_post_type\">registada</a> no tipo de "
+"artigo."
+
+#: ../includes/qtranslate-slug-settings.php:364
+msgid ""
+"For example, the taxonomy <kbd>category</kbd>, in Spanish would be displayed "
+"as <code>http://example.org/es/categoria/taxonomy-name/</code>. If you leave "
+"this blank will use the default option when you <a href=\"http://codex."
+"wordpress.org/Function_Reference/register_taxonomy\">registered</a> the "
+"taxonomy (if you previously setup a base permastruct for <u>categories</u> or "
+"<u>tags</u> in <a href=\"options-permalink.php\">permalinks</a> page, these "
+"bases will be overwritten by the translated ones)."
+msgstr ""
+"Por exemplo, a taxonomia <kbd>categoria</kbd>, em português seria mostrado "
+"como <code>http://exemplo.org/pt/categoria/nome-de-taxonomia/</code>. Se "
+"deixar isto em branco, será usada a opção por omissão <a href=\"http://codex."
+"wordpress.org/Function_Reference/register_taxonomy\">registada</a> na "
+"taxonomia (se previamente configurou a base das ligações permanentes para "
+"<u>categorias</u> ou <u>etiquetas</u> na página <a href=\"options-permalink.php"
+"\">ligações permanentes</a>, estas bases serão sobrepostas pelas traduzidas)."
+
+#: ../includes/qtranslate-slug-settings.php:368
+msgid "The default styles are very minimal, and you can include them or not."
+msgstr "﻿Os estilos padrão são mínimos, pode incluí-los ou não."
+
+#: ../includes/qtranslate-slug-settings.php:567
+msgid ""
+"If you activated previously the <a href=\"options-permalink.php\">pretty "
+"permalinks</a>, in this section you can translate the <abbr title=\"en inglés, "
+"Universal Resource Locator\">URLs</abbr> <strong>bases</strong> for <a href="
+"\"http://codex.wordpress.org/Function_Reference/register_post_type#Arguments"
+"\">public</a> post_types, categories, tags and taxonomies."
+msgstr ""
+"Se activou previamente as <a href=\"options-permalink.php\">ligações "
+"permanentes</a>, nesta secção poderá traduzir as <strong>bases</strong> das "
+"<abbr title=\"em inglês, Universal Resource Locator\">URLs</abbr> para tipos "
+"de artigo, categorias, etiquetas e taxonomias <a href=\"http://codex.wordpress."
+"org/Function_Reference/register_post_type#Arguments\">públicas</a>."
+
+#: ../includes/qtranslate-slug-settings.php:586
+msgid "If you selected \"none\", copy and use these styles as you see fit:"
+msgstr "Se escolher \"nenhum\", copie e utilize estes estilos como entender:"
+
+#: ../includes/qtranslate-slug-settings.php:589
+msgid "Save Changes"
+msgstr "Guardar alterações"
+
+#: ../includes/qtranslate-slug-settings.php:642
+msgid "Expecting a Numeric value! Please fix."
+msgstr "É necessário um valor numérico! Por favor, corrija."
+
+#: ../includes/qtranslate-slug-settings.php:655
+msgid "Expecting comma separated numeric values"
+msgstr "Valores numéricos separados por vírgulas"
+
+#: ../includes/qtranslate-slug-settings.php:665
+msgid "Expecting comma separated numeric values! Please fix."
+msgstr ""
+"São necessários valores numéricos separados por vírgulas! Por favor, corrija."
+
+#: ../includes/qtranslate-slug-settings.php:690
+msgid "Invalid email"
+msgstr "Email incorrecto"
+
+#: ../includes/qtranslate-slug-settings.php:692
+msgid "This setting field cannot be empty! Please enter a valid email address."
+msgstr ""
+"Este campo não pode estar vazio! Por favor introduza um endereço de email "
+"válido."
+
+#: ../includes/qtranslate-slug-settings.php:700
+msgid "Please enter a valid email address."
+msgstr "Por favor introduza um endereço de email válido."
+
+#: ../qtranslate-slug.php:150
+msgid "Settings"
+msgstr "Definições"
diff --git a/languages/qts.pot b/languages/qts.pot
new file mode 100644
index 0000000..cedf142
--- /dev/null
+++ b/languages/qts.pot
@@ -0,0 +1,313 @@
+# Copyright (C) 2012 qTranslate slug
+# This file is distributed under the same license as the qTranslate slug package.
+msgid ""
+msgstr ""
+"Project-Id-Version: qTranslate slug 1.0\n"
+"Report-Msgid-Bugs-To: http://wordpress.org/tag/qtranslate-slug\n"
+"POT-Creation-Date: 2015-01-23 14:23-0000\n"
+"PO-Revision-Date: 2015-01-23 14:23-0000\n"
+"Last-Translator: Pedro Mendonça <ped.gaspar@gmail.com>\n"
+"Language-Team: Carlos Sanz Garcia <carlos.sanz@gmail.com>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Poedit 1.7.3\n"
+"X-Poedit-SourceCharset: UTF-8\n"
+"X-Poedit-KeywordsList: __;_e;__ngettext;_n;__ngettext_noop;_n_noop;_x;_nx;"
+"_nx_noop;_ex;esc_attr__;esc_attr_e;esc_attr_x;esc_html__;esc_html_e;"
+"esc_html_x\n"
+"X-Poedit-Basepath: .\n"
+"X-Poedit-SearchPath-0: .\n"
+"X-Poedit-SearchPath-1: ..\n"
+
+#: ../includes/class-qtranslate-slug-widget.php:11
+msgid "Allows your visitors to choose a Language."
+msgstr ""
+
+#: ../includes/class-qtranslate-slug-widget.php:12
+msgid "Language selector"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug-widget.php:19
+msgid "Language"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug-widget.php:51
+msgid "Title:"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug-widget.php:52
+msgid "Hide Title:"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug-widget.php:53
+msgid "Display:"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug-widget.php:54
+msgid "Text only"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug-widget.php:55
+msgid "Image only"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug-widget.php:56
+msgid "Text and Image"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug-widget.php:57
+msgid "Dropdown Box"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug-widget.php:58
+msgid "Show short name (en):"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug.php:413
+msgid "Please update your old data to the new system."
+msgstr ""
+
+#: ../includes/class-qtranslate-slug.php:413
+#: ../includes/qtranslate-slug-settings.php:29
+msgid "upgrade now"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug.php:427
+msgid "or newer"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug.php:432
+msgid "This plugin requires at least %s and either %s, or %s, or %s"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug.php:432
+msgid "More information about"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug.php:1612
+msgid "View all posts in %s"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug.php:1739
+msgid "Empty Term"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug.php:1999
+#: ../includes/class-qtranslate-slug.php:2000
+#: ../includes/class-qtranslate-slug.php:2003
+#: ../includes/class-qtranslate-slug.php:2541
+msgid "Slug"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug.php:2214
+#: ../includes/class-qtranslate-slug.php:2233
+#: ../includes/qtranslate-slug-settings-options.php:39
+msgid "Slug (%s)"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug.php:2400
+#: ../includes/class-qtranslate-slug.php:2404
+msgid "Name"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug.php:2542
+msgid "Posts"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug.php:2634
+msgid "Languages"
+msgstr ""
+
+#: ../includes/class-qtranslate-slug.php:2657
+msgid "All languages"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings-options.php:14
+msgid "Post types"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings-options.php:15
+msgid "Taxonomies"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings-options.php:16
+msgid "Styles"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings-options.php:63
+msgid "Change styles type"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings-options.php:65
+msgid "adds a file (qts-default.css) to the theme's header."
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings-options.php:66
+msgid ""
+"adds a minified ( slighlty faster) file (qts-default.min.css) to the theme's "
+"header."
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings-options.php:67
+msgid "prints the styles directly into the theme's header."
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings-options.php:68
+msgid "neither include not print the default style."
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings-options.php:73
+msgid "file"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings-options.php:74
+msgid "minified"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings-options.php:75
+msgid "inline"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings-options.php:76
+msgid "none"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings-options.php:106
+#: ../includes/qtranslate-slug-settings-options.php:148
+msgid "<code>http://example.org/<u>%s</u>/some-%s/</code>"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings-options.php:119
+msgid "Categories"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings-options.php:120
+msgid "<code>http://example.org/<u>category</u>/some-category/</code>"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings-options.php:130
+msgid "Tags"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings-options.php:131
+msgid "<code>http://example.org/<u>tag</u>/some-tag/</code>"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings-options.php:175
+msgid "Qtranslate Settings - Contextual Help"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings-options.php:176
+msgid ""
+"Contextual help goes here. You may want to use different html elements to "
+"format your text as you want."
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:23
+msgid "Upgrade your data"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:24
+msgid ""
+"There are slugs stored with old data system. Please upgrade your data pressing "
+"upgrade button:"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:77
+msgid "Sorry, some error happened. Refresh this page and try again please."
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:84
+msgid "Congratulations, your data has been upgraded, you are up to date."
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:90
+msgid "One step more, select what type of slug is this: <strong>%s</strong>"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:91
+msgid "Post, Page or Custom post type"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:91
+msgid "Category, tag or custom taxonomy"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:182
+#: ../includes/qtranslate-slug-settings.php:322
+msgid "Qtranslate Slug options"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:322
+msgid "Slug options"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:359
+msgid ""
+"For example, the post_type <kbd>books</kbd>, in Spanish would be displayed as "
+"<code>http://example.org/es/libros/post-type-name/</code>. If you leave this "
+"blank will use the default option when you <a href=\"http://codex.wordpress."
+"org/Function_Reference/register_post_type\">registered</a> the post_type."
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:364
+msgid ""
+"For example, the taxonomy <kbd>category</kbd>, in Spanish would be displayed "
+"as <code>http://example.org/es/categoria/taxonomy-name/</code>. If you leave "
+"this blank will use the default option when you <a href=\"http://codex."
+"wordpress.org/Function_Reference/register_taxonomy\">registered</a> the "
+"taxonomy (if you previously setup a base permastruct for <u>categories</u> or "
+"<u>tags</u> in <a href=\"options-permalink.php\">permalinks</a> page, these "
+"bases will be overwritten by the translated ones)."
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:368
+msgid "The default styles are very minimal, and you can include them or not."
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:567
+msgid ""
+"If you activated previously the <a href=\"options-permalink.php\">pretty "
+"permalinks</a>, in this section you can translate the <abbr title=\"en inglés, "
+"Universal Resource Locator\">URLs</abbr> <strong>bases</strong> for <a href="
+"\"http://codex.wordpress.org/Function_Reference/register_post_type#Arguments"
+"\">public</a> post_types, categories, tags and taxonomies."
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:586
+msgid "If you selected \"none\", copy and use these styles as you see fit:"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:589
+msgid "Save Changes"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:642
+msgid "Expecting a Numeric value! Please fix."
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:655
+msgid "Expecting comma separated numeric values"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:665
+msgid "Expecting comma separated numeric values! Please fix."
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:690
+msgid "Invalid email"
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:692
+msgid "This setting field cannot be empty! Please enter a valid email address."
+msgstr ""
+
+#: ../includes/qtranslate-slug-settings.php:700
+msgid "Please enter a valid email address."
+msgstr ""
+
+#: ../qtranslate-slug.php:150
+msgid "Settings"
+msgstr ""
diff --git a/qtranslate-slug.php b/qtranslate-slug.php
new file mode 100644
index 0000000..cdfa49e
--- /dev/null
+++ b/qtranslate-slug.php
@@ -0,0 +1,193 @@
+<?php
+/*
+Plugin Name: qTranslate slug
+Plugin URI: http://not-only-code.github.com/qtranslate-slug/
+Description: Allows to define a slug for each language and some qTranslate bug fixes
+Version: 1.1.16
+Author: Carlos Sanz Garcia, Pedro Carvalho 
+Author URI: http://github.com/not-only-code
+*/
+
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+if ( !function_exists('_debug') ):
+function _debug( $message ) {
+	   
+	if ( WP_DEBUG === true ):
+		 
+		if ( is_array( $message ) || is_object( $message ) ) {
+			
+			error_log( print_r( $message, true ) );
+			
+		} else {
+			
+			error_log( $message );
+		}
+			 
+	 endif;
+}
+endif;
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+/**
+ * Includes
+ *
+ * @since 1.1.8
+ */
+include_once(dirname(__FILE__).'/includes/class-qtranslate-slug-widget.php');
+include_once(dirname(__FILE__).'/includes/class-qtranslate-slug.php');
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+/**
+ * Define Constants
+ *
+ * @since 1.0
+ */
+if (!defined("QTS_VERSION")) 		    define("QTS_VERSION", '1.1.12');
+if (!defined("QTS_PREFIX")) 		    define("QTS_PREFIX", '_qts_');
+if (!defined("QTS_PAGE_BASENAME")) 		define('QTS_PAGE_BASENAME', 'qtranslate-slug-settings');
+if (!defined("QTS_OPTIONS_NAME")) 		define("QTS_OPTIONS_NAME", 'qts_options');
+if (!defined("PHP_EOL"))				define("PHP_EOL", "\r\n");
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+/**
+ * Includes
+ *
+ * @since 1.0
+ */
+if ( is_admin() && !QtranslateSlug::block_activate() ) { // setting options page
+	include_once(dirname(__FILE__).'/includes/qtranslate-slug-settings.php'); 
+}
+
+include_once(dirname(__FILE__).'/includes/termmeta-core.php'); // termmeta install and core functions
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+
+	
+/**
+ * Init the plugin
+ *
+ * @since 1.0
+ */	
+global $qtranslate_slug;
+
+$qtranslate_slug = new QtranslateSlug();
+
+// plugin activation
+register_activation_hook( __FILE__, array($qtranslate_slug, 'install') );
+
+// plugin deactivation
+register_deactivation_hook( __FILE__, array($qtranslate_slug, 'deactivate') );
+
+// plugin uninstall
+register_uninstall_hook( __FILE__, 'qts_uninstall' );
+
+// plugin init
+add_action('plugins_loaded', array($qtranslate_slug, 'init') );
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Language Selector Code for templating
+ *
+ * @package Qtranslate Slug
+ * @subpackage Core 
+ * @since 1.0
+ */
+function qts_language_menu ($type = "text", $args = array()) {
+	global $qtranslate_slug;
+	
+	$qtranslate_slug->language_menu($type, $args);
+}
+
+/**
+ * Finds the translated slug of the given post by calling get_slug
+ * @param int $id the post id
+ * @param string $lang which language to look for
+ * @since 1.1.13
+ */ 
+
+function qts_get_slug( $id, $lang ) {
+	global $qtranslate_slug;
+	return $qtranslate_slug->get_slug($id, $lang);
+}
+
+
+/**
+ * Adds support for old plugin function
+ * 
+ * @package Qtranslate Slug
+ * @subpackage Core
+ * @since 1.1.5
+ */
+function qTranslateSlug_getSelfUrl ($lang = false) { // bad naming, I'll keep just in case
+	return qts_get_url($lang);
+}
+
+function qts_get_url($lang = false) {
+	global $qtranslate_slug;
+
+	return $qtranslate_slug->get_current_url($lang);
+}
+
+
+
+/**
+ * Add a "Settings" link to the plugins.php page for Qtranslate Slug
+ *
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0 
+ *
+ * @return calls qts_show_msg()
+ */
+function qts_add_settings_link( $links, $file ) {
+	
+	if (QtranslateSlug::block_activate()) return $links;
+	
+	$this_plugin = plugin_basename( __FILE__ );
+	if( $file == $this_plugin ) {
+		$settings_link = "<a href=\"options-general.php?page=" . QTS_PAGE_BASENAME . "\">" . __( 'Settings', 'qts' ) . '</a>';
+		array_unshift($links, $settings_link);
+	}
+	return $links;
+}
+add_filter( 'plugin_action_links', 'qts_add_settings_link', 10, 2 );
+
+
+
+/**
+ * Delete plugin stored data ( options, termmeta table and postmeta data )
+ *
+ * @package Qtranslate Slug
+ * @subpackage Settings
+ * @version 1.0 
+ *
+ */
+function qts_uninstall() {
+	global $q_config, $wpdb;
+	
+	// options
+	delete_option(QTS_OPTIONS_NAME);
+	delete_option('qts_version');
+	
+	// delete termmeta table
+	$wpdb->query("DROP TABLE IF EXISTS $wpdb->termmeta");
+	
+	// delete postmeta data
+	$meta_keys = array();
+	foreach ($q_config['enabled_languages'] as $lang) $meta_keys[] = sprintf("_qts_slug_%s", $lang);
+	$meta_keys = "'". implode( "','", $meta_keys ) . "'";
+	$wpdb->query("DELETE from $wpdb->postmeta WHERE meta_key IN ($meta_keys)");	
+}
diff --git a/readme.txt b/readme.txt
new file mode 100644
index 0000000..f40439e
--- /dev/null
+++ b/readme.txt
@@ -0,0 +1,278 @@
+=== Qtranslate Slug ===
+Contributors: carlos_a_sanz, pedroghandi  
+Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=SYC46KSLRC4Q8
+Tags: qtranslate, slug, multilanguage, widget
+Requires at least: 3.3
+Tested up to: 4.2.4
+Stable tag: 1.1.17
+License: GPLv2 or later
+License URI: http://www.gnu.org/licenses/gpl-2.0.html
+
+Adds support for permalink translations to QTranslate-X since wordpress 3.0
+
+== Description ==
+
+[Qtranslate-X](http://wordpress.org/plugins/qtranslate-x/) is a nice plugin for Multilingual Websites. **Qtranslate Slug** is an addon to QTranslate, which adds support for permalinks translations.
+
+1.1.17 fixes a dangerous Security Exploit. Please update right now!
+
+= Requirements: =
+
+* Wordpress 3.3 (PHP 5.4 and MySQL 5)
+* mQtranslate 2.6.2.4 or Qtranslate 2.5.8 or qtranslate-x ( 2.9.1 )
+
+= New in 1.1.17 =
+* Hability to filter the position of the Metabox
+* Fixed dangerous security exploit!
+
+= New in 1.1.16 =
+Minor fix for the language menu using qtranslate's function
+
+= New in 1.1.15 =
+* Fixes the duplicated hreflang links in <head>
+
+= New in 1.1.14 =
+
+The menu widget didn't allow the visitors to change to the default language if qtranslate-x was being used. So, adjusted the Language Menu widget to play nice with qtranslate-x. 
+Hope to bring some nice changes that were made in the github repository in the next version. For now, enjoy.
+
+= New in 1.1.13 =
+== Thanks to returning @pedro-mendonca for these commits: ==
+* Cleaned duplicated label in widget
+* Bug fix in "Slug (%s)" string translation
+* Changed text strings with no text-domain and with text-domain 'qtranlate' to text-domain 'qts'
+* pot catalog updated with current strings, including last found is "More information about".
+== Thanks to @johnclause for these : ==
+* Convenience links in notice_dependences
+* Menu compatibility with qTranslate-X
+* Fixed extra characters in widget
+### Thanks to vbkun for casting the much wanted function to get a slug based on an id and language
+* Added a global qts_get_slug( $id, $lang)
+### and sadly:
+* removed the menu admin box until better implementation
+
+
+See you next Version!
+
+
+**Advice: If you're using a multisite installation, you will must activate qtranslate plugins by separately on each site.**
+
+You can also check the [project website](http://not-only-code.github.com/qtranslate-slug/) hosted on [GitHub](http://not-only-code.github.com).
+Thanks for use this plugin!
+
+= Contributors =
+
+* [Pedro de Carvalho](https://github.com/LC43/)
+* [Risto Niinemets](https://github.com/RistoNiinemets)
+* [Pedro Mendonça](https://github.com/pedro-mendonca)
+* [codep0et](https://github.com/codep0et)
+* [Giraldi Maggio](https://github.com/bedex78)
+* [jinoOM](https://github.com/jinoOM)
+* [Juanfran](https://github.com/juanfran-granados)
+* [Arild](https://github.com/arildm)
+* [Rafa Aguilar](https://github.com/rafitaFCB)
+* [Bastian Heist](https://github.com/beheist)
+* [John Clause](https://github.com/johnclause)
+
+
+== Installation ==
+**This plugins requires [Qtranslate](http://wordpress.org/extend/plugins/qtranslate/) or [mqTranslate](https://wordpress.org/plugins/mqtranslate/) installed previously, if not, it will not activate.**
+
+1. Upload `qtranslate-slug` to the `/wp-content/plugins/` directory.
+1. Activate the plugin through the 'Plugins' menu in WordPress.
+1. That's all!
+
+= Changing base permastructs =
+
+1. In admin: navigate to *Settings/Slug options*.
+1. Set the base permastructs for **post types** and **taxonomies** (If you setup a base permastruct for *categories* or *tags* in *Settings/Permalinks*, these will be overwritten by the translated ones).
+1. Save settings and that's all!
+
+== Frequently Asked Questions ==
+
+= It works with posts and pages, but with other content type? =
+
+This plugin allows to translate slugs of: posts, pages, custom post types, categories, tags and custom taxonomies.
+
+= Do I have to configure anything? =
+
+If you want to translate also the base permastructs (ex. *category*, *tag*, etc). Visit the plugin settings page in the admin *Settings/Slug options*
+
+= How can i insert a language selector in my theme ? =
+
+You can choose to:
+* use **Qtranslate Slug Widget** in your sidebar.
+* place in your template `<?php if (function_exists('qts_language_menu') ) qts_language_menu('text'); ?>`. Options are: `dropdown`, `text`, `image`, and `both`.
+
+= Appears an error 404, what can i do? =
+
+In the admin go to *Settings/Permalinks* or *Settings/Slug options* and save.
+
+= I can't manage translations in Nav Menus. = 
+
+That's because language selector metabox is hidden, if you are in admin *nav menus* screen, press the button **Screen options** (on top and right) and after, check the option *Languages*. It will appear a **Language** meta box on top of the left sidebar.
+
+= How to get the current url in a specific language? =
+
+You can use `qts_get_url()` or the awkwardly named `qTranslateSlug_getSelfUrl()` which is an alias for the first one.
+
+
+== Screenshots ==
+
+1. Edit page for: post / page / post_type, you can see the meta box for translated slugs on top and right.
+2. Add new taxonomy page
+3. Edit taxonomy page
+4. Qtranslate Slug options page for translate base permastructs of post_types and taxonomies.
+
+== Changelog ==
+
+
+= New in Versions 1.1.12 =
+
+* fixed warnings in settings
+* replace qtranslate with our own for taxonomies
+
+= New in Versions 1.1.10 and 1.1.11 =
+
+* Fixing wrong commit to wp.org
+* Clean deleted files 
+= New in Version 1.1.9 =
+
+Lots of bug fixes! Thanks again to everyone that contributed to this project, with commits, bug reports and suggestions.
+
+* Compatibility with qtranslate-X! ( thanks @beheist, pull #85, fixing most of #80 )
+* More updates to the portuguese translation ( thanks pedro-mendonca, pull #86)
+* Corrected the link to language files ( thanks pedro-mendonca )
+* Added translation for some hardcoded texts ( thanks pedro-mendonca )
+* Corrected a link from 'qtranslate' to 'qts' language files ( thanks pedro-mendonca )
+* Fixed taxonomies slugs ( thanks to [eirikv's bug report](https://wordpress.org/support/topic/categories-slug-dont-work) )
+* Fixed many warnings ( thanks piffpaffpuff, issue #78 and to [pedrodu1](https://wordpress.org/support/topic/warnings-qtranslate-slugphp) )
+* Changed the behaviour of "Quick Edit", from the wp forums [1](https://wordpress.org/support/topic/categories-tags-and-quick-edit-dont-show-in-admin) [2](https://wordpress.org/support/topic/quick-edit-inhibited-by-qtranslate-slug-with-wp-41-mqtranslate) ( thanks everyone!! )
+* Fixed the menus! Now you can properly use one menu for every language. Use the dropdown section "Languages", and for each item, change the "Navigation Label" and "Title Attribute". Select "All languages", to make sure everything is awesome! All these features were a consequence of fixing all the warnings based on [Gery's bug report](https://wordpress.org/support/topic/qtranslate-slug-conflicting-with-ubermenu). 
+* Minor fixes, etc. 
+
+
+= New in Version 1.1.9 =
+
+Lots of bug fixes! Thanks again to everyone that contributed to this project, with commits, bug reports and suggestions.
+
+* Compatibility with qtranslate-X! ( thanks @beheist, pull #85, fixing most of #80 )
+* More updates to the portuguese translation ( thanks pedro-mendonca, pull #86)
+* Corrected the link to language files ( thanks pedro-mendonca )
+* Added translation for some hardcoded texts ( thanks pedro-mendonca )
+* Corrected a link from 'qtranslate' to 'qts' language files ( thanks pedro-mendonca )
+* Fixed taxonomies slugs ( thanks to [eirikv's bug report](https://wordpress.org/support/topic/categories-slug-dont-work)
+* Fixed many warnings ( thanks piffpaffpuff, issue #78 and to [pedrodu1](https://wordpress.org/support/topic/warnings-qtranslate-slugphp) )
+* Changed the behaviour of "Quick Edit", from the wp forums [1](https://wordpress.org/support/topic/categories-tags-and-quick-edit-dont-show-in-admin) [2](https://wordpress.org/support/topic/quick-edit-inhibited-by-qtranslate-slug-with-wp-41-mqtranslate) ( thanks everyone!! )
+* Fixed the menus! Now you can properly use one menu for every language. Use the dropdown section "Languages", and for each item, change the "Navigation Label" and "Title Attribute". Select "All languages", to make sure everything is awesome! All these features were a consequence of fixing all the warnings based on [Gery's bug report)[https://wordpress.org/support/topic/qtranslate-slug-conflicting-with-ubermenu). 
+* Minor fixes, etc. 
+
+See you next Version!
+
+
+= 1.1.8 =
+
+Many thanks to everyone that contributed to this update, for their commits, bug reports and for simply using it
+
+* Portuguese translation and fixed some translation bugs  ( thanks pedro-mendonca )
+* removed mqtranslate switcher widget hook
+* Updated the plugin structure and coding style
+* solve some conflicts with search and pagination queries
+* Settings php errors, syntax indent and fixed settings assets url
+* Change titles when there is a click on pagination on show all pages tab ( thanks juanfran-granados )
+* Formatted dependency notice message ( thanks arildm )
+* Updated the deprecated jquery 'live' function and solve php strict standards error ( thanks rafitaFCB )  
+* Fixed error showing if PHP was newer than 5.3 ( thanks rafitaFCB )  
+* Strict standard advise prevented ( thanks rafitaFCB )
+* php notices are prevented in post edit, when using adding new translated tags  ( thanks rafitaFCB )
+* fixed the hreflang issue! 'bout time!
+* As discussed in issue #25, the flags are now img tags, intead of background-url.
+* Added another option to include the css style in a minified file. ( and also showing in the option screen the styles we would use.)
+
+= 1.1.7 = 
+* removed styles from html elements and added options to use .css file or print inline styles
+* fixed tag creation on post edit.
+* fixed earlier bad post slug introduced in 1.1.6
+
+= 1.1.6 =
+* compatible with mqtranslate
+* php5.4+ compatible
+
+= 1.1.5 = 
+* bugfixes
+
+= 1.1 = 
+* added multisite support
+* fixed some parse url bugs
+* fixed slug bases validation 
+
+= 1.0 =
+* **works** with any permalink combination and qtranslate mode.
+* new branch, the plugin has been rewritten: now the code is commented and wrapped inside a class, much code has change and the performance has been increased (use caches).
+* data system changed, no ID for slug type, then it don't needs install `qtrasnlate_slug` table. That means slugs now are stored on meta tables and installation creates a termmeta table with some new *core functions* to access/save data, based on [simple term meta](http://wordpress.org/extend/plugins/simple-term-meta/). Upgrade process when the plugin updates from older versions.
+* the plugin generates translated slug automatically from title in empty cases.
+* the plugin checks if the slug already exists (per each language and `post_type`/`taxonomy`), and adds a progressive number in this case. Works on ajax requests for example when new taxonomies are created in edit post page.
+* possibility to translate the base of permastructs for *post_types* and *taxonomies*, uses [$wp_rewrite](http://codex.wordpress.org/Class_Reference/WP_Rewrite). New admin options page for save the base permastructs.
+* added some filters, see in [other notes](http://wordpress.org/extend/plugins/qtranslate-slug/other_notes/).
+* added plugin language textdomain (.pot file).
+* updated **Language selector Widget**, and some new conventions like accessible functions for templating.
+* some bug fixes.
+* some Qtranslate patches.
+
+= 0.9 =
+* some wordpress qTranslate bug fixes
+* adds a javascript solution for qTranslate Nav Menus
+
+= 0.8 =
+* added support por Categories
+* added support por Tags
+* added support por Taxonomies
+* added support por Custom Post Types
+
+= 0.7 = [Zapo](http://www.qianqin.de/qtranslate/forum/viewtopic.php?f=4&t=1049&start=50#p7499)
+* added suport for qTranslate TLD domain mode (en: domain.com | fr: domain.fr) visit 
+
+= 0.5 and 0.6 enhanched by Marco Del Percio =
+
+== Upgrade Notice ==
+
+= 1.0 =
+Major version, the plugin has been rewritten. Better performance, and some enhancements.
+
+= 0.9 =
+This version fix some bugs and allow multilanguage in nav-menus.
+
+= 0.8 =
+A lot of slugs content allowed
+
+= 0.7 =
+This version allows TLD domain option for a different Qtranslate fork maded by Zappo
+
+
+== Other notes ==
+
+Plugin filters reference:
+
+= qts_validate_post_slug =  
+filter to process the post slug before is saved on the database.  
+`args: $post (object), $slug (string), $lang (string)`
+
+= qts_validate_term_slug =  
+filter to process the term slug before is saved on the database.  
+`args: $term (object), $slug (string), $lang (string)`
+
+= qts_url_args =  
+filter to process the entire url after it has been generated.  
+`args: $url (string), $lang (string)`
+ 
+= qts_permastruct =  
+filter to process the permastruct, used for change the base.  
+`args: $permastruct (string), $name (string)`
+
+
+= Todo =
+
+* detect Slug for each language and redirect accordingly in parse_query.
+* expand qtranslate for translate attachment names and descriptions ( useful for galleries )
+* translate other slugs like attachments.
+* qtranslate integration with other plugins like Jigoshop, e-commerce, etc. Addapt **$wp_rewrite**.
diff --git a/screenshot-1.png b/screenshot-1.png
new file mode 100644
index 0000000..26b1d03
Binary files /dev/null and b/screenshot-1.png differ
diff --git a/screenshot-2.png b/screenshot-2.png
new file mode 100644
index 0000000..1c65e54
Binary files /dev/null and b/screenshot-2.png differ
diff --git a/screenshot-3.png b/screenshot-3.png
new file mode 100644
index 0000000..1e68461
Binary files /dev/null and b/screenshot-3.png differ
diff --git a/screenshot-4.png b/screenshot-4.png
new file mode 100644
index 0000000..87ea7a9
Binary files /dev/null and b/screenshot-4.png differ
diff --git a/version.txt b/version.txt
new file mode 100644
index 0000000..3b0e860
--- /dev/null
+++ b/version.txt
@@ -0,0 +1,127 @@
+= New in 1.1.17 =
+* Fixed dangerous security exploit!
+* Hability to filter the position of the Metabox
+
+= New in 1.1.16 =
+Minor fix for the language menu using qtranslate's function
+
+= New in 1.1.15 =
+* Fixes the duplicated hreflang links in <head>
+
+= New in 1.1.14 =
+
+The menu widget didn't allow the visitors to change to the default language if qtranslate-x was being used. So, adjusted the Language Menu widget to play nice with qtranslate-x. 
+Hope to bring some nice changes that were made in the github repository in the next version. For now, enjoy.
+
+= 1.1.13 =
+== Thanks to returning @pedro-mendonca for these commits: ==
+* Cleaned duplicated label in widget
+* Bug fix in "Slug (%s)" string translation
+* Changed text strings with no text-domain and with text-domain 'qtranlate' to text-domain 'qts'
+* pot catalog updated with current strings, including last found is "More information about".
+== Thanks to @johnclause for these : ==
+* Convenience links in notice_dependences
+* Menu compatibility with qTranslate-X
+* Fixed extra characters in widget
+== Thanks to vbkun for casting this much wanted function ==
+* Added a global qts_get_slug( $id, $lang)
+== and sadly: ==
+* removed the menu admin box until better implementation
+
+= 1.1.12 =
+
+* fixed warnings in settings
+* replace qtranslate with our own for taxonomies
+
+= 1.1.10 and 1.1.11 =
+* Fixing wrong commit to wp.org
+* Clean deleted files
+
+= 1.1.9  =
+
+Lots of bug fixes! Thanks again to everyone that contributed to this project, with commits, bug reports and suggestions.
+
+* Compatibility with qtranslate-X! ( thanks @beheist, pull #85, fixing most of #80 )
+* More updates to the portuguese translation ( thanks pedro-mendonca, pull #86)
+* Corrected the link to language files ( thanks pedro-mendonca )
+* Added translation for some hardcoded texts ( thanks pedro-mendonca )
+* Corrected a link from 'qtranslate' to 'qts' language files ( thanks pedro-mendonca )
+* Fixed taxonomies slugs ( thanks to [eirikv's bug report](https://wordpress.org/support/topic/categories-slug-dont-work) )
+* Fixed many warnings ( thanks piffpaffpuff, issue #78 and to [pedrodu1](https://wordpress.org/support/topic/warnings-qtranslate-slugphp) )
+* Changed the behaviour of "Quick Edit", from the wp forums [1](https://wordpress.org/support/topic/categories-tags-and-quick-edit-dont-show-in-admin) [2](https://wordpress.org/support/topic/quick-edit-inhibited-by-qtranslate-slug-with-wp-41-mqtranslate) ( thanks everyone!! )
+* Fixed the menus! Now you can properly use one menu for every language. Use the dropdown section "Languages", and for each item, change the "Navigation Label" and "Title Attribute". Select "All languages", to make sure everything is awesome! All these features were a consequence of fixing all the warnings based on [Gery's bug report](https://wordpress.org/support/topic/qtranslate-slug-conflicting-with-ubermenu). 
+* Minor fixes, etc. 
+
+See you next Version!
+
+= 1.1.8 =
+
+Many thanks to everyone that contributed to this update, both for their commits and bug reports )
+
+* Portuguese translation and fixed some translation bugs  ( thanks pedro-mendonca )
+* removed mqtranslate switcher widget hook
+* Updated the plugin structure and coding style
+* solve some conflicts with search and pagination queries
+* Settings php errors, syntax indent and fixed settings assets url
+* Change titles when there is a click on pagination on show all pages tab ( thanks juanfran-granados )
+* Formatted dependency notice message ( thanks arildm )
+* Updated the deprecated jquery 'live' function and solve php strict standards error ( thanks rafitaFCB )  
+* Fixed error showing if PHP was newer than 5.3 ( thanks rafitaFCB )  
+* Strict standard advise prevented ( thanks rafitaFCB )
+* php notices are prevented in post edit, when using adding new translated tags  ( thanks rafitaFCB )
+* fixed the hreflang issue! 'bout time!
+* As discussed in issue #25, the flags are now img tags, intead of background-url.
+* Added another option to include the css style in a minified file. ( and also showing in the option screen the styles we would use.)
+
+= 1.1.7 = 
+* removed styles from html elements and added options to use .css file or print inline styles
+* fixed tag creation on post edit.
+* fixed earlier bad post slug introduced in 1.1.6
+
+= 1.1.6 =
+* compatible with mqtranslate
+* php5.4+ compatible
+
+= 1.1.5 = 
+* bugfixes
+
+= 1.1 = 
+* added multisite support
+* fixed some parse url bugs
+* fixed slug bases validation 
+
+= 1.0 =
+* new branch, the plugin has been rewrited: now the code is commented and wrapped inside a class, also all code has change and the performance has been increased.
+* structural changes:
+	* no ID for slug type, then don't install qtrasnlate_slug table.
+	* slugs now are stored on meta tables, installation creates a termmeta table with some new 'core functions' to access/save data, based on [simple term meta](http://wordpress.org/extend/plugins/simple-term-meta/).
+* some automation:
+	* the plugin generates translated slug automatically from title in empty cases (like wordpress).
+	* the plugin checks if the slug already exists (per each language and type / taxonomy), and adds a progressive number in this case (like wordpress).
+	* works on ajax requests like creatig new taxonomies on edit post page.
+* possibility to translate the base of permastructs for 'post_types' and 'taxonomies' (uses $wp_rewrite).
+* added some filters:
+	* 'qts_validate_post_slug' : args( $post (object), $slug (string), $lang (string) ) / filter to process the post slug before is saved on the database.
+	* 'qts_validate_term_slug' : args( $term (object), $slug (string), $lang (string) ) / filter to process the term slug before is saved on the database.
+	* 'qts_current_url' : args ( $url (string), $lang (string) ) / filter to process the entire url after it has been generated.
+	* 'qts_permastruct' : args ( $permastruct (string), $name (string) ) / filter to process the permastruct, used for change the base.
+* added plugin language textdomain (.pot file)
+* new admin options page for save the base permastructs.
+* import process when the plugin updates older versions.
+* some bug fixes.
+* some Qtranslate patches.
+
+= 0.9 =
+* some wordpress qTranslate bug fixes
+* adds a javascript solution for qTranslate Nav Menus
+
+= 0.8 =
+* added support por Categories
+* added support por Tags
+* added support por Taxonomies
+* added support por Custom Post Types
+
+= 0.7 ( enhanced by Zapo (http://www.qianqin.de/qtranslate/forum/viewtopic.php?f=4&t=1049&start=50#p7499) ) =
+* added suport for qTranslate TLD domain mode (en: domain.com | fr: domain.fr) visit 
+
+= 0.5 and 0.6 enhanched by Marco Del Percio =
\ No newline at end of file

Fixed code: .qts_type_image .qts_lang_item { 
    float: left;
    margin-right: 7px;
}
.qts_type_image .qts_lang_item.last-child {
    margin-right: 0;
}
.qts_lang_item{
    margin-top: 7px;
    margin-bottom: 7px;
}
.qts_both {
    white-space: nowrap;
    line-height:1em;
}
.qts_both img { margin-right: 4px }
.qts_type_image .qts_lang_item{float:left;margin-right:7px}.qts_type_image .qts_lang_item.last-child{margin-right:0}.qts_lang_item{margin-top:7px;margin-bottom:7px}.qts_both{white-space:nowrap;line-height:1em}.qts_both img{margin-right:4px}
/*messages*/
.error {color:#cc0000;}

.form-table th  {
	width: 15%;
	min-width: 15% !important;
}

.form-table td > span {
	display: inline-block;
	min-width: 100px;
}

.form-table label {
	display: block;
	margin-bottom: 8px;
}

.qts-slug {
	width: 35%;
}

#qts-loading {
	display: none;
	position: relative;
	margin-left: 5px;
	vertical-align: middle;
}

div.updated.success{
	border-color: #298e00;
	background-color: #D4EDC9;
}

.error a.button-primary {
	color: white !important;
	text-decoration: none !important;
}

.ko {
	color: #c00;
}
jQuery(document).ready(function(t){function i(){t(".item-title").each(function(){n[t(this).closest("li").attr("id")]=[],n[t(this).closest("li").attr("id")].Title=t(this).find("span").html(),"undefined"==typeof n[t(this).closest("li").attr("id")].Original&&(n[t(this).closest("li").attr("id")].Original=n[t(this).closest("li").attr("id")].Title)}),t(".menu-item").each(function(){this_label=t(this).find("input.edit-menu-item-title"),this_title=t(this).find("input.edit-menu-item-attr-title"),n[t(this).attr("id")][this_label.attr("id")]=this_label.val(),n[t(this).attr("id")][this_title.attr("id")]=this_title.val()})}function e(){regexp=new RegExp("<!--:"+d+"-->(.*?)<!--:-->","i"),t(".item-title").each(function(){(matches=n[t(this).closest("li").attr("id")].Original.match(regexp))&&t(this).closest("li").find(".link-to-original a").text(matches[1])}),regexp2=new RegExp("<!--:"+d+"-->(.*?)<!--:-->","i"),t(".menu-item").each(function(){this_label=t(this).find("input.edit-menu-item-title"),this_title=t(this).find("input.edit-menu-item-attr-title"),"all"===d?(this_label.val(n[t(this).attr("id")][this_label.attr("id")]),this_title.val(n[t(this).attr("id")][this_title.attr("id")])):((matches=n[t(this).attr("id")][this_label.attr("id")].match(regexp2))&&this_label.val(matches[1]),(matches2=n[t(this).attr("id")][this_title.attr("id")].match(regexp2))&&this_title.val(matches2[1]))})}function a(){t(".menu-item").each(function(){this_label=t(this).find("input.edit-menu-item-title"),this_title=t(this).find("input.edit-menu-item-attr-title"),this_label.val(n[t(this).attr("id")][this_label.attr("id")]),this_title.val(n[t(this).attr("id")][this_title.attr("id")]),t(this).find(".link-to-original a").text(n[t(this).closest("li").attr("id")].Original)})}var n=[],s=wpNavMenu.addMenuItemToBottom;wpNavMenu.addMenuItemToBottom=function(t,a){s(t,a),i(),e()};var l=wpNavMenu.addMenuItemToTop;wpNavMenu.addMenuItemToTop=function(t,a){l(t,a),i(),e()};var d=t("#qt-languages :radio:checked").val();i(),e(),t(document).ajaxComplete(function(){d=t("#qt-languages :radio:checked").val(),e()}),t("#qt-languages :radio").change(function(){d=t("#qt-languages :radio:checked").val(),e()}),t(".submit-add-to-menu").click(function(){d=t("#qt-languages :radio:checked").val(),e()}),t(document.body).on("change","input.edit-menu-item-title",null,function(){regexp=new RegExp("<!--:"+d+"-->(.*?)<!--:-->","i");var i=n[t(this).closest("li").attr("id")][t(this).attr("id")],e=t(this).val();regexp.test(i)&&(n[t(this).closest("li").attr("id")][t(this).attr("id")]=i.replace(regexp,"<!--:"+d+"-->"+e+"<!--:-->"))}),t(document.body).on("change","input.edit-menu-item-attr-title",null,function(){regexp=new RegExp("<!--:"+d+"-->(.*?)<!--:-->","i");var i=n[t(this).closest("li").attr("id")][t(this).attr("id")],e=t(this).val();qts_new_string="<!--:"+d+"-->"+e+"<!--:-->","undefined"==typeof i||""==i?(n[t(this).closest("li").attr("id")][t(this).attr("id")]=qts_new_string,t(this).val(qts_new_string)):regexp.test(i)?n[t(this).closest("li").attr("id")][t(this).attr("id")]=i.replace(regexp,qts_new_string):(t(this).val(i+qts_new_string),n[t(this).closest("li").attr("id")][t(this).attr("id")]=i+qts_new_string)}),t(".menu-save").click(function(){a()}),window.onbeforeunload=function(){a()}});
jQuery(document).ready(function($){
	var qts_menuitemlang = [];
	// Change titles (and values) when user add new item to the menu:
	var oldAddMenuItemToBottom = wpNavMenu.addMenuItemToBottom;
	wpNavMenu.addMenuItemToBottom = function( menuMarkup, req ) {
		oldAddMenuItemToBottom( menuMarkup, req );
		saveLang();
		changeTitles();
	};
	var oldAddMenuItemToTop = wpNavMenu.addMenuItemToTop;
	wpNavMenu.addMenuItemToTop = function( menuMarkup, req ) {
		oldAddMenuItemToTop( menuMarkup, req );
		saveLang();
		changeTitles();
	};
	
	// Change titles (and values) when document is ready:
	var lang = $('#qt-languages :radio:checked').val();
	saveLang();
	changeTitles();
        
  /**
  * Change titles when there is a click on pagination
  * on show all pages tab.
  * 
  * It happens when there are a large number of pages.
  */
  $( document ).ajaxComplete(function() {
      lang = $('#qt-languages :radio:checked').val();
      changeTitles();
  });
	
	// Change titles (and values) when language is changed:
	$('#qt-languages :radio').change( function() {
		lang = $('#qt-languages :radio:checked').val();
		
		changeTitles();
	});
	
	// Change titles (and values) when new menu is added:
	$('.submit-add-to-menu').click( function() {
		lang = $('#qt-languages :radio:checked').val();
		changeTitles();
	});
		
	// Update original value when user changed a value:
	$(document.body).on('change', 'input.edit-menu-item-title', null, function() {
		regexp = new RegExp('<!--:' + lang + '-->(.*?)<!--:-->', 'i');
		
		
		var qts_old_value = qts_menuitemlang[ $(this).closest("li").attr("id") ][ $(this).attr("id")],
		    qts_new_value = $(this).val();
		
		  if( regexp.test(qts_old_value ) ) {
		    qts_menuitemlang[ $(this).closest("li").attr("id") ][  $(this).attr("id")] = qts_old_value.replace( regexp,'<!--:' + lang + '-->' + qts_new_value + '<!--:-->');  
		  }
			
	});
	
	
	
	
	// Update original title="" value when user changed a value:
	$(document.body).on('change', 'input.edit-menu-item-attr-title', null, function() {
		regexp = new RegExp('<!--:' + lang + '-->(.*?)<!--:-->', 'i');
		var qts_old_value = qts_menuitemlang[ $(this).closest("li").attr("id") ][ $(this).attr("id")],
		    qts_new_value = $(this).val();
		    qts_new_string = '<!--:' + lang + '-->'+ qts_new_value + '<!--:-->';
    if(typeof qts_old_value === "undefined"  || qts_old_value == "" ) { 
      qts_menuitemlang[ $(this).closest("li").attr("id") ][ $(this).attr("id")] =  qts_new_string;
      $(this).val( qts_new_string );
	  } else if( regexp.test(qts_old_value ) ) {
	    qts_menuitemlang[ $(this).closest("li").attr("id") ][  $(this).attr("id")] = qts_old_value.replace( regexp,qts_new_string);
	  } else {
	    $(this).val( qts_old_value + qts_new_string );
	    qts_menuitemlang[ $(this).closest("li").attr("id") ][  $(this).attr("id")] = qts_old_value + qts_new_string;
	  }
			
	});
	
	
	
	// Change titles (and values):
	function saveLang() {
	    $('.item-title').each( function() {
	      qts_menuitemlang[ $(this).closest("li").attr("id") ] = [];
	      qts_menuitemlang[ $(this).closest("li").attr("id") ]['Title'] =  $(this).find("span").html();
	      
	      if( typeof qts_menuitemlang[ $(this).closest("li").attr("id") ]['Original'] === "undefined" ) {
	        qts_menuitemlang[ $(this).closest("li").attr("id") ]['Original'] =  qts_menuitemlang[ $(this).closest("li").attr("id") ]['Title'];
	      }
      });
      $('.menu-item').each( function() {
        
        this_label = $(this).find('input.edit-menu-item-title');
        this_title = $(this).find('input.edit-menu-item-attr-title');
        
        qts_menuitemlang[ $(this).attr("id") ][this_label.attr("id") ] = this_label.val();
        qts_menuitemlang[ $(this).attr("id") ][this_title.attr("id") ] = this_title.val();
        
      });
      
	}
	// Change titles (and values):
	function changeTitles() {
		// Change menu item titles and links (on the right side):
		// TODO: review, and dump
		regexp = new RegExp('<!--:' + lang + '-->(.*?)<!--:-->', 'i');
		$('.item-title').each( function() {
			  if (matches = qts_menuitemlang[ $(this).closest("li").attr("id") ]['Original'].match(regexp)) {
          $(this).closest('li').find('.link-to-original a').text( matches[1] );		
			  }
			
		});
		// Change menu item title inputs (on the right side): Navigation Label, Title Attribute...
		regexp2 = new RegExp('<!--:' + lang + '-->(.*?)<!--:-->', 'i');
		$('.menu-item').each( function() {
		  this_label = $(this).find('input.edit-menu-item-title');
      this_title = $(this).find('input.edit-menu-item-attr-title');
		  if( lang === "all") {
          this_label.val(qts_menuitemlang[ $(this).attr("id") ][this_label.attr("id") ] );
          this_title.val(qts_menuitemlang[ $(this).attr("id") ][this_title.attr("id") ] );
      } else {
               
        if (matches = qts_menuitemlang[ $(this).attr("id") ][this_label.attr("id") ].match(regexp2)) {
            this_label.val( matches[1] );
        }
		 
        if (matches2 = qts_menuitemlang[ $(this).attr("id") ][this_title.attr("id") ].match(regexp2)) {
            this_title.val( matches2[1] ); 
        }
			}
		});
		
		// Change menu item checkbox labels (on the left side):
		// TODO: fix this, not a show stopper
		/*$('label.menu-item-title').each( function() {
			var textNode = $(this).contents().get(1);
		});*/
	}

	// Restore the original input values:
	function restoreValues(){ 
		  
		  $('.menu-item').each( function() {
		      
		    this_label = $(this).find('input.edit-menu-item-title');
        this_title = $(this).find('input.edit-menu-item-attr-title');
        
        this_label.val( qts_menuitemlang[ $(this).attr("id") ][this_label.attr("id") ] );
        this_title.val( qts_menuitemlang[ $(this).attr("id") ][this_title.attr("id") ] );
          $(this).find('.link-to-original a').text( qts_menuitemlang[ $(this).closest("li").attr("id") ]['Original']);
      });
	}
	
	// Just before saving restore the original input values:
	$('.menu-save').click(function() {
		restoreValues();
	});

	// Just before leaving the page (or refresh) restore the original input values:
	window.onbeforeunload = function(){ 
		restoreValues();		
		return;
	};

});
jQuery(document).ready(function($) {
	
	function _debug(msg) {
		if(window.console) {
			console.debug(msg);
		}
	}
	var upgrade_box = $('#qts-upgrade-box'),
	upgrade_form = $('#qts-upgrade-form'),
	upgrade_button = $('#qts-upgrade-button'),
	notice_status = function(_status) {
		upgrade_box.removeClass().addClass(_status);
	},
	block_form = function(_block) {
		if (_block) {
			$('#qts-loading').show();
			upgrade_button.attr('disabled', true);			
		} else {
			$('#qts-loading').hide();
			upgrade_button.attr('disabled', false);
		}

	},
	check_types = function(_response) {
		
		block_form(false);
		upgrade_form.find('.message').remove();
		
		switch (_response.status) {
			default:
			case 0:
				upgrade_form.prepend('<p class=\'message ko\'>'+_response.message+'</p>');
			break;
			case 1:
				notice_status('updated success');
				upgrade_form.remove();
				upgrade_box.append('<p><strong>'+_response.message+'</strong></p>');
				upgrade_box.delay(2500).fadeTo(1300, 0, function(){ upgrade_box.remove(); });
			break;
			case 2:
				var data_ = '<p class=\'message\'>'+_response.message+'</p>';
				data_ += '<select id=\'qts-slug-type\' class=\'message\'>';
				
				for (opt in _response.options) 
					data_ += '<option value=\''+opt+'\'>'+_response.options[opt]+'</option>';
				data_ += '</select>';
				
				upgrade_form.prepend(data_);
				
			break;
		}
	},
	start_upgrade = function(_event) {
		_event.preventDefault();
		
		notice_status('updated');
		block_form(true);
		
		var package_ = {};
		package_.action = $('#qts-upgrade-action').val(); 
		package_.nonce = $('#qts-upgrade-nonce').val();
		if ( $('#qts-slug-type').length )
			package_.type = $('#qts-slug-type').val();
			
		$.post(ajaxurl, package_, check_types);
	};
	
	upgrade_button.bind('click', start_upgrade);
});
/*############### Error messages ######################*/	
jQuery(function(){
	
	var error_msg = jQuery("#message p[class='setting-error-message']");
	// look for admin messages with the "setting-error-message" error class
	if (error_msg.length != 0) {
		// get the title
		var error_setting = error_msg.attr('title');
		
		// look for the label with the "for" attribute=setting title and give it an "error" class (style this in the css file!)
		jQuery("label[for='" + error_setting + "']").addClass('error');
		
		// look for the input with id=setting title and add a red border to it.
		jQuery("input[id='" + error_setting + "']").attr('style', 'border-color: red');
	}	
	
	
	
});
<?php

/**
 * QtranslateSlug_Widget class
 *
 * @since 1.0
 */
class QtranslateSlugWidget extends WP_Widget {
     
    function QtranslateSlugWidget() {
        $widget_ops = array('classname' => 'qts_widget', 'description' => __('Allows your visitors to choose a Language.','qts') );
        $this->WP_Widget('qtranslateslug', __('Language selector', 'qts'), $widget_ops);
    }
    
    function widget($args, $instance) {
        extract($args);
        
        echo $before_widget;
        $title = empty($instance['title']) ? __('Language', 'qts') : apply_filters('widget_title', $instance['title']);
        $hide_title = empty($instance['hide-title']) ? false : 'on';
        $type = $instance['type'];
        $short_text = ($instance['short_text'] == 'on') ? true : false ;
        
        if( $type!='text' && $type!='image' && $type!='both' && $type!='dropdown' ) $type='text';

        if( $hide_title!='on')
            echo $before_title . $title . $after_title;
        
        qts_language_menu($type, array( 'id' => $this->id, 'short' => $short_text ) );
        
        echo $after_widget;
    }
    
    function update($new_instance, $old_instance) {
        $instance = $old_instance;
        $instance['title'] = $new_instance['title'];
        $instance['hide-title'] = $new_instance['hide-title'];
        $instance['type'] = $new_instance['type'];
        $instance['short_text'] = $new_instance['short_text'];

        return $instance;
    }
    
    function form($instance) {
        $instance = wp_parse_args( (array) $instance, array( 'title' => '', 'hide-title' => false, 'type' => 'text' ) );
        $title = $instance['title'];
        $hide_title = $instance['hide-title'];
        $type = $instance['type'];
        $short_text = isset($instance['short_text']) ? $instance['short_text'] : '';
 ?>
        <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:', 'qts'); ?> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($title); ?>" /></label></p>
        <p><label for="<?php echo $this->get_field_id('hide-title'); ?>"><?php _e('Hide Title:', 'qts'); ?> <input type="checkbox" id="<?php echo $this->get_field_id('hide-title'); ?>" name="<?php echo $this->get_field_name('hide-title'); ?>" <?php echo ($hide_title=='on')?'checked="checked"':''; ?>/></label></p>
        <p><?php _e('Display:', 'qts'); ?></p>
        <p><label for="<?php echo $this->get_field_id('type'); ?>1"><input type="radio" name="<?php echo $this->get_field_name('type'); ?>" id="<?php echo $this->get_field_id('type'); ?>1" value="text"<?php echo ($type=='text')?' checked="checked"':'' ?>/> <?php _e('Text only', 'qts'); ?></label></p>
        <p><label for="<?php echo $this->get_field_id('type'); ?>2"><input type="radio" name="<?php echo $this->get_field_name('type'); ?>" id="<?php echo $this->get_field_id('type'); ?>2" value="image"<?php echo ($type=='image')?' checked="checked"':'' ?>/> <?php _e('Image only', 'qts'); ?></label></p>
        <p><label for="<?php echo $this->get_field_id('type'); ?>3"><input type="radio" name="<?php echo $this->get_field_name('type'); ?>" id="<?php echo $this->get_field_id('type'); ?>3" value="both"<?php echo ($type=='both')?' checked="checked"':'' ?>/> <?php _e('Text and Image', 'qts'); ?></label></p>
        <p><label for="<?php echo $this->get_field_id('type'); ?>4"><input type="radio" name="<?php echo $this->get_field_name('type'); ?>" id="<?php echo $this->get_field_id('type'); ?>4" value="dropdown"<?php echo ($type=='dropdown')?' checked="checked"':'' ?>/> <?php _e('Dropdown Box', 'qts'); ?></label></p>
        <p><label for="<?php echo $this->get_field_id('short_text'); ?>"><?php _e('Show short name (en):', 'qts'); ?> <input type="checkbox" id="<?php echo $this->get_field_id('short_text'); ?>" name="<?php echo $this->get_field_name('short_text'); ?>" <?php checked($short_text, 'on')  ?>/></label></p>

 <?php
    }
}
<?php

/**
 * QtranslateSlug class
 *
 * @since 1.0
 */
class QtranslateSlug {
    
    
    /**
     * array with old data system
     *
     * @var bool
     *
     * @since 1.0
     */
    private $old_data = null;
    
    
    
    /**
     * stores permalink_structure option, for save queries to db
     *
     * @var string
     *
     * @since 1.0
     */
    private $permalink_structure;
    
    
    
    /**
     * Stores options slugs from database
     *
     * @var array
     *
     * @since 1.0
     */
    protected $options;
    
    
    
    /**
     * Variable used to override the language
     *
     * @var string
     *
     * @since 1.0
     */
    private $lang = false;
	
	/**
	 * variable for current language
	 */
    private $current_lang = false;
    
    /**
	 * variable for default language
	 */
    private $default_language = false;
    
	/**
     * Array of enabled languages
     *
     * @var array
     *
     * @since 1.0
     */
    private $enabled_languages = array();
	/**
     * Array of enabled languages
     *
     * @var array
     *
     * @since 1.0
     */
    private $url_path_mode = "";
	
    
    
    /**
     * slug in meta_key name in meta tables
     *
     * @var string
     *
     * @since 1.0
     */
    private $meta_key = "_qts_slug_%s";
    
    
    
    /**
     * Array of translated versions of the current url
     *
     * @var array
     *
     * @since 1.0
     */
    private $current_url = array();
    
    
    /**
     * Variable that contains the prefix for base plugin function names (qtranslate/qtranslate-x)
     *
     * @var string
     *
     * @since ?
     */
    private $plugin_prefix = "";
	
	
    /**
     * return the current / temp language
     *
     * @since 1.0
     */
    private function get_lang() {
        global $q_config;
        
        return ($this->lang) ? $this->lang : $q_config['language'];
    }
    /**
     * return the current / temp language
	 * we store and use it all the way!
     *
     * @since 1.1.9
     */
    private function get_currentlang() {
        return $this->current_lang;
    }
    /**
     * return the enabled languages
	 * we store and use it all the way!
     *
     * @since 1.1.9
     */
    private function get_enabled_languages() {
        return $this->enabled_languages;
    }
    /**
     * return the enabled languages
	 * we store and use it all the way!
     *
     * @since 1.1.9
     */
    private function get_url_path_mode() {
        return $this->url_path_mode;
    }
    
    
    /**
     * getter: options
     *
     * @since 1.0
     */
    public function get_options() {
        $this->set_options();
        return $this->options;
    }

    /**
     * Returns the correct prefix for the function names of the different supported translation plugins.
     * Will return 'qtranxf_' if qtranslate-x is used, 'qtrans_' otherwise.
     *
     * @return string the function name prefix for translation functions from other plugins
     * @since 1.1.9
     */

    private function get_plugin_prefix(){
        
        return $this->plugin_prefix;
    }
    
    
    /**
     * setter: options | permalink_structure
     *
     * @since 1.0
     */
    public function set_options() {

        if (empty($this->options)) {
            $this->options = get_option(QTS_OPTIONS_NAME);
        }

        if (!$this->options) {
            add_option(QTS_OPTIONS_NAME, array());
        }
        
        if (is_null($this->permalink_structure)) {
            $this->permalink_structure = get_option('permalink_structure');
        }
    }
    
    /**
	 * Sets the prefix for the active fork. See get_plugin_prefix
	 * @since 1.1.9
	 *
	 */
    private function set_plugin_prefix(){
        if ('' === $this->plugin_prefix){
            if (is_plugin_active('qtranslate-x/qtranslate.php')){
                $this->plugin_prefix = 'qtranxf_';
            } else {
                $this->plugin_prefix = 'qtrans_';
            }
        }
    }

    /**
     * Sets the url path mode based on the qtranslate or fork settings.
     *
     */

    private function set_url_path_mode(){
        if ('' === $this->url_path_mode){
            if (is_plugin_active('qtranslate-x/qtranslate.php')){
                $this->url_path_mode = QTX_URL_PATH;
            } else {
                $this->url_path_mode = QT_URL_PATH;
            }
        }
    }
    
    /**
     * setter: options | permalink_structure
     *
     * @since 1.0
     */
    public function save_options($new_options = false) {
        if (!$new_options || empty($new_options)) {
            return;
        }
        
        if (count($this->options) != count($new_options)) {
            return;
        }
        
        update_option(QTS_OPTIONS_NAME, $new_options);
        $this->options = $new_options;
    }
    
    
    
    /**
     * getter: meta key
     *
     * @since 1.0
     */
    public function get_meta_key( $force_lang = false ) {
        global $q_config;
        
        $lang = $this->get_lang();
        
        if ($force_lang) {
            $lang = $force_lang;
        }
       
        return sprintf($this->meta_key, $lang); // returns: _qts_slug_en
    }
    
    
    
    /**
     * check dependences for activation
     *
     * @since 1.0
     */
    static function block_activate() {
        global $wp_version;
        
        include_once( ABSPATH . 'wp-admin/includes/plugin.php' ); 
        
        return (
            version_compare($wp_version, "3.3", "<" ) ||
                ( !is_plugin_active('qtranslate/qtranslate.php') && 
                !is_plugin_active('mqtranslate/mqtranslate.php') && 
                !is_plugin_active('qtranslate-x/qtranslate.php'))
        );
    }
    
    
	
    
    /**
     * check if exists qtranslate and do the installation, support multisite
     *
     * @since 1.0
     */
    public function install() {
        global $wpdb;
        
        if ( self::block_activate() ) {
            return;
        }
        
        if ( function_exists('is_multisite') && is_multisite() ) {

            if (isset($_GET['networkwide']) && ($_GET['networkwide'] == 1)) {
                
                $old_blog = $wpdb->blogid;
                $blogids = $wpdb->get_col($wpdb->prepare("SELECT blog_id FROM $wpdb->blogs"));
                foreach ($blogids as $blog_id) {
                    switch_to_blog($blog_id);
                    $this->activate();
                }
                switch_to_blog($old_blog);
                return;
            }
        }
        
        $this->activate();
    }
    
    
    
    /**
     * activates and do the installation
     *
     * @since 1.0
     */
    private function activate() {
        global $wp_rewrite;

        $this->set_options();
        
        $qts_version = get_option('qts_version');
        
        // checks version and do the installation
        if ( !$qts_version || $qts_version != QTS_VERSION ) {
            
            // install termmeta table using functions from Simple-Term-Meta 
            // ( http://wordpress.org/extend/plugins/simple-term-meta/ )
            install_term_meta_table();
            
            // update installed option  
            update_option('qts_version', QTS_VERSION);
        }
    
        // regenerate rewrite rules in db
        add_action( 'generate_rewrite_rules', array(&$this, 'modify_rewrite_rules') );
        flush_rewrite_rules();
    }
  
    

    /**
    * register front end styles and enqueue
    *
    * @since 1.1.7
    */
    public function register_plugin_styles() {
		wp_register_style( 'qts_front_styles', plugins_url( '/assets/css/qts-default.css', dirname(__FILE__ ) ) );
        wp_enqueue_style( 'qts_front_styles' );
    }
    /**
    * register minified front end styles and enqueue
    * 43LC: easier duplicating the function :|
    * @since 1.1.8
    */
    public function register_plugin_styles_min() {
		wp_register_style( 'qts_front_styles', plugins_url( '/assets/css/qts-default.min.css', dirname(__FILE__ ) ) );
        wp_enqueue_style( 'qts_front_styles' );
    }



    /**
    * print front end styles
    *
    * @since 1.1.7
    */
    public function print_plugin_styles() {

        $css_path = dirname(__FILE__).'/assets/css/qts-default.css';

        if (!file_exists($css_path) || !is_readable($css_path)) {
            return;
        }

        $default_css_file = file_get_contents($css_path, FILE_USE_INCLUDE_PATH);

        $css = "<style media=\"screen\">\n";
        $css .= "$default_css_file\n";
        $css .="</style>\n";
        echo $css;
    }
  
    

    /**
     * actions when deactivating the plugin
     *
     * @since 1.0
     */
    public function deactivate() {
        global $wp_rewrite;
        
        // regenerate rewrite rules in db
        remove_action( 'generate_rewrite_rules', array(&$this, 'modify_rewrite_rules') );
        $wp_rewrite->flush_rules();
    }
    


    /**
     * admin notice: update your old data 
     *
     * @since 1.0
     */
    function notice_update(){
        global $current_screen;
        
        if ($current_screen->id != 'settings_page_qtranslate-slug-settings') {
        
            echo "<div class=\"updated\">" . PHP_EOL;
            echo "<p><strong>Qtranslate Slug:</strong></p>" . PHP_EOL;
            printf("<p>%s <a href=\"%s\" class=\"button\">%s</a></p>", __('Please update your old data to the new system.', 'qts'), add_query_arg(array('page' => 'qtranslate-slug-settings'), 'options-general.php'), __('upgrade now', 'qts')) . PHP_EOL;
            echo "</div>" . PHP_EOL;
        }
    }
    
    
    
    /**
     * admin notice: update your old data 
     *
     * @since 1.0
     */
    function notice_dependences(){
        global $current_screen;
        $ornewer=__('or newer','qts');
        $info_url=admin_url('plugin-install.php?tab=plugin-information');
        echo '<div class="error">' . PHP_EOL;
        echo '<p><strong>Qtranslate Slug:</strong></p>' . PHP_EOL;
        echo '<p>';
        printf(__('This plugin requires at least %s and either %s, or %s, or %s', 'qts'),'<strong>WordPress 3.3</strong>','<a href="'.$info_url.'&plugin=qtranslate-x&TB_iframe=true" class="thickbox" aria-label="'.__('More information about', 'qts').' '.'qTranslate-X" data-title="qTranslate-X"><strong>qTranslate-X</strong></a> (2.9 '.$ornewer.')','<a href="'.$info_url.'&plugin=mqtranslate&TB_iframe=true" class="thickbox" aria-label="'.__('More information about', 'qts').' '.'mqTranslate" data-title="mqTranslate"><strong>mqTranslate</strong></a> (2.6.2.4 '.$ornewer.')','<a href="'.$info_url.'&plugin=qtranslate&TB_iframe=true" class="thickbox" aria-label="'.__('More information about', 'qts').' '.'qTranslate" data-title="qTranslate"><strong>qTranslate</strong></a> (2.5.8 '.$ornewer.')');
        echo '</p>' . PHP_EOL;
        echo '</div>' . PHP_EOL; 
    }
    
    
    
    /**
     * checks if old table 'qtranslate_slug' exists and is not empty
     * 
     * @return object | false
     *
     * @since 1.0
     */
    public function check_old_data() {
        global $wpdb;
        
        if ($this->old_data === false) {
            return false;
        }
                    
        $table_name = $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}qtranslate_slug'");
            
        if (!empty($table_name)) {
            $this->old_data = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}qtranslate_slug");
        }
        
        if ( empty($table_name) || empty($this->old_data) ) {
            $this->old_data = false;
        }
        
        return $this->old_data;
    }
    
    
    
    /**
     * actions when deactivating the plugin
     *
     * @since 1.0
     */
    private function check_old_versions() {
        
        if ( $this->check_old_data() ) {
            add_action('admin_notices', array(&$this, 'notice_update'));
        }
    }
    
    
    
    /**
     * Initialise the Class with all hooks
     *
     * @since 1.0
     */
    function init() {
      
		load_plugin_textdomain( 'qts', false, basename( plugin_dir_path( dirname( __FILE__ ) ) ) . '/languages' );
        
        // checking plugin activate
        if ( self::block_activate() ) {
            if (is_admin()) {
                add_action('admin_notices', array(&$this, 'notice_dependences'));
            }
            return;
        }
    
        // caching qts options
        $this->set_options();
        
		global $q_config;
		
		// until we get  a proper function, this will make it for it.
		$this->current_lang = $q_config['language'];
	    $this->enabled_languages = $q_config['enabled_languages'];
        $this->default_language  = $q_config['default_language'];
		$this->set_plugin_prefix();
		$this->set_url_path_mode();
		
        if ( is_admin() ) {
            
            $this->check_old_versions();
       
            
            // add filters
            add_filter( 'qts_validate_post_slug', array(&$this, 'validate_post_slug'), 0, 3 );
            add_filter( 'qts_validate_post_slug', array(&$this, 'unique_post_slug'), 1, 3 );
            add_filter( 'qts_validate_term_slug', array(&$this, 'validate_term_slug'), 0, 3 );
            add_filter( 'qts_validate_term_slug', array(&$this, 'unique_term_slug'), 1, 3 );
            add_filter( 'wp_get_object_terms', array(&$this, 'get_object_terms'), 0, 4 );
            add_filter( 'get_terms', array(&$this, 'get_terms'), 0, 3 );
            
            // admin actions
            add_action( 'admin_menu', array(&$this, 'add_slug_meta_box') );
            add_action( 'save_post', array(&$this, 'save_postdata'), 605, 2 );
            add_action( 'delete_term', array(&$this, 'delete_term'), 0, 3);
            add_action( 'created_term', array(&$this, 'save_term'), 605, 3);
            add_action( 'edited_term', array(&$this, 'save_term'), 605, 3 );
            add_action( 'admin_head', array(&$this, 'hide_slug_box'), 900 );
            
            add_action( 'init', array(&$this, 'taxonomies_hooks'), 805 );
            
            add_action( 'wp_dashboard_setup', array(&$this, 'remove_dashboard_widgets') );
            add_action( 'admin_head', array(&$this, 'hide_quick_edit'), 600 );
            if(!defined('QTRANSLATE_FILE'))
              add_action( 'admin_init', array(&$this, 'fix_nav_menu') );
            
        } else {
            
            add_filter( 'request', array(&$this, 'filter_request') );

            // adds external style file
            $qts_options = $this->get_options();
            if ( !isset($qts_options[QTS_PREFIX.'styles']) || $qts_options[QTS_PREFIX.'styles'] == "file" ) {
                add_action( 'wp_enqueue_scripts', array( &$this, 'register_plugin_styles' ) );
            } elseif ($qts_options[QTS_PREFIX.'styles'] == "minified" ) {
                add_action( 'wp_enqueue_scripts', array( &$this, 'register_plugin_styles_min' ) );
            } elseif ($qts_options[QTS_PREFIX.'styles'] == "inline" ) {
                add_action( 'wp_print_styles', array( &$this, 'print_plugin_styles' ), 20 );
            }
        }
        
        add_filter( 'query_vars', array(&$this, 'query_vars'));
        add_action( 'generate_rewrite_rules', array(&$this, 'modify_rewrite_rules') );
        
        // remove from qtranslate the discouraged meta http-equiv, inline styles
        // (including flag URLs) and wrong hreflang links   
        
        remove_action('wp_head', $this->get_plugin_prefix() . 'header');
        if( "qtranxf_" === $this->get_plugin_prefix() ) {
            remove_action('wp_head', $this->get_plugin_prefix() . 'head');
        }
        
        // add proper hreflang links
        add_action('wp_head',array(&$this, 'qtranslate_slug_header_extended'));
        
        // remove some Qtranslate filters
        remove_filter( 'page_link',     $this->get_plugin_prefix() . 'convertURL' );
        remove_filter( 'post_link',     $this->get_plugin_prefix() . 'convertURL' );
        remove_filter( 'category_link', $this->get_plugin_prefix() . 'convertURL' );
        remove_filter( 'tag_link',      $this->get_plugin_prefix() . 'convertURL' );
        
        add_filter( 'qts_permastruct' , array(&$this, 'get_extra_permastruct'), 0, 2);
        add_filter( 'qts_url_args',     array(&$this, 'parse_url_args'), 0, 1);
        add_filter( 'home_url',         array(&$this, 'home_url'), 10, 4);  
        add_filter( 'post_type_link',   array(&$this, 'post_type_link'), 600, 4 );
        add_filter( 'post_link',        array(&$this, 'post_link'), 0, 3 );
        add_filter( '_get_page_link',   array(&$this, '_get_page_link'), 0, 2 );
        add_filter( 'term_link',        array(&$this, 'term_link'), 600, 3 );
        
        add_filter( 'single_term_title', $this->get_plugin_prefix() . 'useTermLib', 805 );
        add_filter( 'get_blogs_of_user', array(&$this, 'blog_names'), 1  );
        add_action( 'widgets_init', array(&$this, 'widget_init'), 100 );
        // Add specific CSS class to body class based on current lang
        add_filter('body_class', array($this, 'qts_body_class'), 600, 1 );
        
        add_filter( 'nav_menu_attr_title', array($this, 'qts_filter_attr_title'), 0, 3 );


    }
      
     /**
     * Filters menu link attribute
     *  
     * @since 1.1.9
     */ 
    function qts_filter_attr_title( $attr_title ) {
        return $this->qts_quickuse($attr_title);
    }


    /**
     * Adds proper links to the content with available translations.
     * Fixes issue #25
     *  
     * @global $qtranslate_slug used to convert the url
     * @global $q_config available languages
     *
     * @since 1.1.8
     */ 
    public function qtranslate_slug_header_extended(){
    	if(is_404()) return;
        
        //taken from qtx 
        echo '<link hreflang="x-default" href="'.$this->get_current_url($this->default_language) .'" rel="alternate" />'.PHP_EOL;
        foreach($this->get_enabled_languages() as $language) {

            if($language != $this->get_currentlang() )
                echo '<link hreflang="'.$language.'" href="'.$this->get_current_url($language).'" rel="alternate" />'."\n";
        }
    }
    

    /**
     * Add a class based on the current language
     * @param array $classes list of classes
     */
    public function qts_body_class( $classes ) {
        // add 'class-name' to the $classes array
        $classes[] = call_user_func($this->get_plugin_prefix() . 'getLanguage');
        
        // return the $classes array
        return $classes;
    }

		/**
     * Finds the translated slug of the given post 
     * based on: https://wordpress.org/support/topic/permalink-for-other-languages 
     * @param int $id the post id
     * @param string $lang which language to look for
		 * @return string the slug or empty if not found
     * @author vbkun
     * @since 1.1.13
     */ 
		public function get_slug($id, $lang){
			$slugArray = get_post_meta( $id, '_qts_slug_'.$lang );
			return !empty($slugArray) ? $slugArray[0] : "";
		}

	// TODO: properly test this
	/**
	 * Get text in $lang, or in the current lang
	 *
	 * @package Qtranslate Slug
	 * @since 1.1.9
	 * @param string $text the whole text
	 * @param string $lang (optional) get the text in this language, or if empty, the current
	 * @return array the text in the required language
	 */
	public function qts_quickuse( $text,$lang='' ){
	    global $q_config;
	    $lang = '' == $lang ? $q_config['language'] : $lang;
	    $parsed_text = call_user_func($this->get_plugin_prefix() . 'getSortedLanguages',$text);
	    if( !empty($parsed_text[$lang])){
	      return $parsed_text[$lang];  
	    }  
	}
	

    /**
     * Adds news rules to translate the URL bases, 
     * this function must be called on flush_rewrite or 'flush_rewrite_rules' 
     * 
     * @param object $wp_rewrite
     *
     * @since 1.0
     */ 
    public function modify_rewrite_rules() {
        // do we need this global?	
        //global $wp_rewrite;
        
        // post types rules
        $post_types = get_post_types( array('_builtin' => false ), 'objects');
        foreach ( $post_types as $post_type ) {
            $this->generate_extra_rules( $post_type->name );
        }
        
        // taxonomies rules
        $taxonomies = $this->get_public_taxonomies();
        foreach ( $taxonomies as $taxonomy ) {
            $this->generate_extra_rules( $taxonomy->name );
        }
    }
    
    
    
    /**
     * Helper: news rules to translate the URL bases
     * 
     * @param string $name name of extra permastruct
     * @param string $type 'post_type' or 'taxonomy'
     *
     * @since 1.0
     */
    private function generate_extra_rules( $name = false ) {
        global $wp_rewrite;
        
        foreach ($this->get_enabled_languages() as $lang):
            
            if ( $base = $this->get_base_slug( $name, $lang) ):
                
                $struct = $wp_rewrite->extra_permastructs[$name];
                
                if ( is_array( $struct ) ) {
                    if ( count( $struct ) == 2 )
                        $rules = $wp_rewrite->generate_rewrite_rules( "/$base/%$name%", $struct[1] );
                    else
                        $rules = $wp_rewrite->generate_rewrite_rules( "/$base/%$name%", $struct['ep_mask'], $struct['paged'], $struct['feed'], $struct['forcomments'], $struct['walk_dirs'], $struct['endpoints'] );
                } else {
                    $rules = $wp_rewrite->generate_rewrite_rules( "/$base/%$name%" );
                }
                
                $wp_rewrite->rules = array_merge($rules, $wp_rewrite->rules);
            
            endif;
            
        endforeach;
    }
    
    
    
    /**
     * Helper that gets a base slug stored in options
     * 
     * @param string $name of extra permastruct
     * @return string base slug for 'post_type' and 'language' or false
     *
     * @since 1.0
     */
    public function get_base_slug($name = false, $lang = false) {
        
        if ( !$name || !$lang ) {
            return false;
        }
        
        if ( taxonomy_exists($name) ) {
            $type = 'taxonomy';
        } else if ( post_type_exists($name) ) {
            $type = 'post_type';
        } else {
            return false;
        }
        
        $qts_options = $this->get_options();
        
        $option_name = QTS_PREFIX . $type . '_' . $name;
        
        if ( !isset($qts_options[$option_name]) || empty($qts_options[$option_name]) ) {
            return false;
        }
        
        if (isset($qts_options[$option_name][$lang])) {
            return $qts_options[$option_name][$lang];
        }
        
        return false;
    }
    
    
    
    /**
     * Helper: returns public built-in and not built-in taxonomies
     * 
     * @return array of public taxonomies objects
     *
     * @since 1.0
     */
    private function get_public_taxonomies() {
        
        $builtin = get_taxonomies( array( 'public' => true, 'show_ui' => true, '_builtin' => true ), 'object'); 
        $taxonomies = get_taxonomies( array( 'public' => true, 'show_ui' => true, '_builtin' => false ), 'object' ); 
        
        return array_merge( $builtin, $taxonomies );
    }
    
    
    
    /**
     * parse and adds $_GET args passed to an url
     * 
     * @param string $url parameters
     * @param string $lang processed
     * @return string converted url
     *
     * @since 1.0
     */
    public function parse_url_args( $url ) {
        global $q_config;

        if (is_admin()) {
            return $url;
        }
        
        $url = preg_replace('/&amp;/', '&', $url);
        
        // if no permalink structure ads ?lang=en
        $base_query = parse_url($q_config['url_info']['original_url']);
        $base_args = isset($base_query['query']) ? wp_parse_args($base_query['query']) : array();
        
        if ( empty($this->permalink_structure) || $q_config['url_mode'] == 1 ) {
            $base_args['lang'] = $this->get_lang();

        }

        // rebuild query with all args
        $url = add_query_arg($base_args, $url);

        $url = str_replace('/?', '?', $url); // TODO: hack: improve this code
        $url = str_replace('?', '/?', $url); // TODO: hack: improve this code
        
        return $url;
    }
    
    
    
    /**
     * Fix get_page_by_path when querying vars
     * 
     * @param $query_vars objec query vars founded
     * @return object $query_vars processed
     *
     * @since 1.0
     */
    public function query_vars( $query_vars ) {
        global $wp, $wp_rewrite;

        $wp->query_vars = array();
        $post_type_query_vars = array();

        // Fetch the rewrite rules.
        $rewrite = $wp_rewrite->wp_rewrite_rules();

        if ( ! empty($rewrite) ) {
            // If we match a rewrite rule, this will be cleared.
            $error = '404';
            $wp->did_permalink = true;

            if ( isset($_SERVER['PATH_INFO']) ) {
                $pathinfo = $_SERVER['PATH_INFO'];
            } else {
                $pathinfo = '';
            }
            $pathinfo_array = explode('?', $pathinfo);
            $pathinfo = str_replace("%", "%25", $pathinfo_array[0]);
            $req_uri = $_SERVER['REQUEST_URI'];
            $req_uri_array = explode('?', $req_uri);
            $req_uri = $req_uri_array[0];
            $self = $_SERVER['PHP_SELF'];
            $home_path = parse_url(home_url());
            
            if ( isset($home_path['path']) ) {
                $home_path = $home_path['path'];
            } else {
                $home_path = '';
            }
            $home_path = trim($home_path, '/');

            // Trim path info from the end and the leading home path from the
            // front. For path info requests, this leaves us with the requesting
            // filename, if any. For 404 requests, this leaves us with the
            // requested permalink.
            $req_uri = str_replace($pathinfo, '', $req_uri);
            $req_uri = trim($req_uri, '/');
            $req_uri = preg_replace("|^$home_path|", '', $req_uri);
            $req_uri = trim($req_uri, '/');
            if ($GLOBALS['q_config']['url_mode'] == $this->get_url_path_mode()) {
                $req_uri = preg_replace("/^{$GLOBALS['q_config']['language']}(\/|$)/", '', $req_uri);
            }
            $pathinfo = trim($pathinfo, '/');
            $pathinfo = preg_replace("|^$home_path|", '', $pathinfo);
            $pathinfo = trim($pathinfo, '/');
            $self = trim($self, '/');
            $self = preg_replace("|^$home_path|", '', $self);
            $self = trim($self, '/');

            // The requested permalink is in $pathinfo for path info requests and
            //  $req_uri for other requests.
            if ( ! empty($pathinfo) && !preg_match('|^.*' . $wp_rewrite->index . '$|', $pathinfo) ) {
                $request = $pathinfo;
            } else {
                // If the request uri is the index, blank it out so that 
                // we don't try to match it against a rule.
                if ( $req_uri == $wp_rewrite->index )
                    $req_uri = '';
                $request = $req_uri;
            }
            
            $wp->request = $request;

            // Look for matches.
            $request_match = $request;
            if ( empty( $request_match ) ) {
                // An empty request could only match against ^$ regex
                if ( isset( $rewrite['$'] ) ) {
                    $wp->matched_rule = '$';
                    $query = $rewrite['$'];
                    $matches = array('');
                }
            } else if ( $req_uri != 'wp-app.php' ) {
                foreach ( (array) $rewrite as $match => $query ) {
                    // If the requesting file is the anchor of the match, prepend it to the path info.
                    if ( ! empty($req_uri) && strpos($match, $req_uri) === 0 && $req_uri != $request ) {
                        $request_match = $req_uri . '/' . $request;
                    }

                    if ( preg_match("#^$match#", $request_match, $matches) || preg_match("#^$match#", urldecode($request_match), $matches) ) {

                        if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
                            // this is a verbose page match, lets check to be sure about it
                            if ( ! $page_foundid = $this->get_page_by_path( $matches[ $varmatch[1] ] ) ) {
                                continue;
                            } else {
                                wp_cache_set('qts_page_request', $page_foundid); // caching query :)
                            }       
                        }

                        // Got a match.
                        $wp->matched_rule = $match;
                        break;
                    }
                }
            }

            if ( isset( $wp->matched_rule ) ) {
                // Trim the query of everything up to the '?'.
                $query = preg_replace("!^.+\?!", '', $query);

                // Substitute the substring matches into the query.
                $query = addslashes(WP_MatchesMapRegex::apply($query, $matches));

                $wp->matched_query = $query;

                // Parse the query.
                parse_str($query, $perma_query_vars);

                // If we're processing a 404 request, clear the error var
                // since we found something.
                unset( $_GET['error'] );
                unset( $error );
            }

            // If req_uri is empty or if it is a request for ourself, unset error.
            if ( empty($request) || $req_uri == $self || strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) {
                unset( $_GET['error'] );
                unset( $error );

                if ( isset($perma_query_vars) && strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) {
                    unset( $perma_query_vars );
                }

                $wp->did_permalink = false;
            }
        }

        return count(array_diff($query_vars, $wp->public_query_vars)) > 0 ? $query_vars : $wp->public_query_vars;
    }
    
    
    
    /**
     * Function called when query parameters are processed by Wordpress.
     * 
     * @param $query query parameters
     * @return array() $query processed
     *
     * @since 1.0
     */
    function filter_request( $query ) {
        global $wp_query, $wp;
        if ((isset($wp->matched_query) || empty($query))  && ! isset($query['s']) ) {
            $query = wp_parse_args($wp->matched_query);
        }
        
        foreach (get_post_types() as $post_type) {
            if ( array_key_exists($post_type, $query) && !in_array($post_type, array('post', 'page')) ) {
                $query['post_type'] = $post_type;
            }
        }
        
        $page_foundit = false;
        
        // -> page
        if ( isset($query['pagename']) || isset($query['page_id']) ):
            
            $page = wp_cache_get('qts_page_request');
            if (!$page) 
                $page = isset($query['page_id']) ? get_post($query['page_id']) : $this->get_page_by_path($query['pagename']);
            
            if (!$page) return $query;
            $id = $page->ID;
            $cache_array = array($page);
            update_post_caches($cache_array, 'page'); // caching query :)
            wp_cache_delete('qts_page_request');
            $query['pagename'] = get_page_uri($page);
            $function = 'get_page_link';
        
        // -> custom post type
        elseif ( isset($query['post_type']) ):
            
            $page_slug = ( isset($query['name']) && !empty($query['name']) ) ? $query['name'] : $query[$query['post_type']];
            $page = $this->get_page_by_path($page_slug, OBJECT, $query['post_type']);
            if (!$page) return $query;
            $id = $page->ID;
            $cache_array = array($page);
            update_post_caches($cache_array, $query['post_type']); // caching query :)
            $query['name'] = $query[$query['post_type']] = get_page_uri($page); 
            $function = 'get_post_permalink';
        
        // -> post
        elseif ( isset($query['name']) || isset($query['p']) ):
            
            $post = isset($query['p']) ? get_post($query['p']) : $this->get_page_by_path($query['name'], OBJECT, 'post');
            if (!$post) {
                return $query;
            }
            $query['name'] = $post->post_name;
            $id = $post->ID;
            $cache_array = array($post);
            update_post_caches($cache_array);
            $function = 'get_permalink';
            
        // -> category
        elseif ( ( isset($query['category_name']) || isset($query['cat'])) ):
            if ( isset($query['category_name']) ) {
                $term_slug = $this->get_last_slash( $query['category_name'] );
            }
            $term = isset($query['cat']) ? get_term($query['cat'], 'category') : $this->get_term_by('slug', $term_slug, 'category');
            if (!$term) {
                return $query;
            }
            $cache_array = array($term);
            update_term_cache($cache_array, 'category'); // caching query :)
            $id = $term->term_id;
            $query['category_name'] = $term->slug; // uri
            $function = 'get_category_link';
        
        // -> tag
        elseif ( isset($query['tag']) ):
            
            $term = $this->get_term_by('slug', $query['tag'], 'post_tag');
            if (!$term) {
                return $query;
            }
            $cache_array = array($term);
            update_term_cache($cache_array, 'post_tag'); // caching query :)
            $id = $term->term_id;
            $query['tag'] = $term->slug;
            $function = 'get_tag_link';
        
        endif;

        
        // -> taxonomy
        $taxonomies = get_taxonomies( array( 'public' => true, '_builtin' => false )  );
        foreach ($taxonomies as $term_name):
        if ( isset($query[$term_name]) ) {
            
            $term_slug = $this->get_last_slash( $query[$term_name] );
            $term = $this->get_term_by('slug', $term_slug, $term_name);
            if (!$term) {
                return $query;
            }
            $cache_array = array($term);
            update_term_cache($cache_array, $term_name); // caching query :)
            $id = $term;
            $query[$term_name] = $term->slug;
            $function = 'get_term_link';
            
        }
        endforeach;

        // -> home url
        if ( empty($query) ) {
            
            $function = 'home_url';
            $id = '';
            
        }
        
        // -> search
        if (isset($query['s'])) {

          $id = $query['s'];
          $function="get_search_link";
      
        }
        
        if ( isset($function) ) {
                    
            // parse all languages links
            foreach( $this->get_enabled_languages() as $lang ) {
                
                $this->lang = $lang;
                $this->current_url[$lang] = esc_url(apply_filters('qts_url_args', call_user_func($function, $id)));
            }

            $this->lang = false;
        }
        
        return $query;
    }
    
    
    
    /**
     * Parse a hierarquical name and extract the last one
     *
     * @param string $lang Page path
     * @return string
     *
     * @since 1.0
     */
    public function get_current_url( $lang = false ) {
        
        if (!$lang) {
            $lang = $this->get_lang();
        }
        
        if (isset($this->current_url[$lang]) && !empty($this->current_url[$lang])) {
            return $this->current_url[$lang];
        }
        
        return '';
    }
    
    
    
    /**
     * Parse a hierarquical name and extract the last one 
     *
     * @param string $slug Page path
     * @return string
     *
     * @since 1.0
     */
    private function get_last_slash($slug) {
        
        $slug = rawurlencode( urldecode( $slug ) );
        $slug = str_replace('%2F', '/', $slug);
        $slug = str_replace('%20', ' ', $slug);
        $exploded_slug = explode('/', $slug);

        return array_pop( $exploded_slug );
    }
    
    
    
    /**
     * Retrieves a page id given its path.
     *
     * @param string $page_path Page path
     * @param string $output Optional. Output type. OBJECT, ARRAY_N, or ARRAY_A. Default OBJECT.
     * @param string $post_type Optional. Post type. Default page.
     * @return mixed Null when complete.
     *
     * @since 1.0
     */
    private function get_page_id_by_path($page_path, $output = OBJECT, $post_type = 'page') {
        global $wpdb;

        $page_path = rawurlencode(urldecode($page_path));
        $page_path = str_replace('%2F', '/', $page_path);
        $page_path = str_replace('%20', ' ', $page_path);
        $parts = explode( '/', trim( $page_path, '/' ) );
        $parts = array_map( 'esc_sql', $parts );
        $parts = array_map( 'sanitize_title_for_query', $parts );
        $in_string = "'". implode( "','", $parts ) . "'";
        $meta_key = $this->get_meta_key();
        $post_type_sql = $post_type;
        $wpdb->escape_by_ref( $post_type_sql );
        
        $pages = $wpdb->get_results( "SELECT $wpdb->posts.ID, $wpdb->posts.post_parent, $wpdb->postmeta.meta_value FROM $wpdb->posts,$wpdb->postmeta WHERE $wpdb->posts.ID = $wpdb->postmeta.post_id AND $wpdb->postmeta.meta_key = '$meta_key' AND $wpdb->postmeta.meta_value IN ($in_string) AND ($wpdb->posts.post_type = '$post_type_sql' OR $wpdb->posts.post_type = 'attachment')", OBJECT_K );

        $revparts = array_reverse( $parts );

        $foundid = 0;
        foreach ( (array) $pages as $page ) {
            if ( $page->meta_value == $revparts[0] ) {
                $count = 0;
                $p = $page;
                while ( $p->post_parent != 0 && isset( $pages[ $p->post_parent ] ) ) {
                    $count++;
                    $parent = $pages[ $p->post_parent ];
                    if ( ! isset( $revparts[ $count ] ) || $parent->meta_value != $revparts[ $count ] ) {
                        break;
                    }
                    $p = $parent;
                }

                if ( $p->post_parent == 0 && $count+1 == count( $revparts ) && $p->meta_value == $revparts[ $count ] ) {
                    $foundid = $page->ID;
                    break;
                }
            }
        }
        
        if ( $foundid ) {
            return $foundid;
            
        } else {
            
            $last_part = array_pop($parts);
            $page_id = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_name = '$last_part' AND (post_type = '$post_type_sql' OR post_type = 'attachment')" );
            
            if ( $page_id ) {
                return $page_id;
            }
        }

        return null;
    }
    
    
    
    
    /**
     * Retrieves a page given its path.
     *
     * @param string $page_path Page path
     * @param string $output Optional. Output type. OBJECT, ARRAY_N, or ARRAY_A. Default OBJECT.
     * @param string $post_type Optional. Post type. Default page.
     * @return mixed Null when complete.
     *
     * @since 1.0
     */
    private function get_page_by_path($page_path, $output = OBJECT, $post_type = 'page') {
        
        $foundid = $this->get_page_id_by_path($page_path, $output, $post_type);
        if ( $foundid ) {
            return get_post( $foundid, $output );
        }
        
        return null;
    }
    
    
    
    /**
     * Ignores if the mod_rewrite func is the caller
     *
     * @return boolean
     *
     * @since 1.0
     */
    private function ignore_rewrite_caller() {
        
        $backtrace = debug_backtrace();
        
        $ignore_functions = array('mod_rewrite_rules', 'save_mod_rewrite_rules', 'flush_rules', 'rewrite_rules', 'wp_rewrite_rules', 'query_vars');
        
        if ( isset($backtrace['function']) ) {
            if (in_array($backtrace['function'], $ignore_functions)) {
                return true;
            }
        } else {
            foreach ($backtrace as $trace) {
                if ( isset($trace['function']) && in_array($trace['function'], $ignore_functions) ) {
                    return true;
                }
            }
        }
        
        return false;
    }
    
    
    /**
     * Retrieve the home url for a given site.
     *
     * @param  int $blog_id   (optional) Blog ID. Defaults to current blog.
     * @param  string $path   (optional) Path relative to the home url.
     * @param  string $scheme (optional) Scheme to give the home url context. Currently 'http', 'https'.
     * @return string Home url link with optional path appended.
     *
     * @since 1.0
     */
    public function home_url($url, $path, $scheme, $blog_id) {
        if ( !in_array( $scheme, array( 'http', 'https' ) ) ) {
            $scheme = is_ssl() && !is_admin() ? 'https' : 'http';
        }

        if ( empty( $blog_id ) || !is_multisite() ) {
            $url = get_option( 'home' );
        } else {
            $url = get_blog_option( $blog_id, 'home' );
        }

        if ( 'http' != $scheme ) {
            $url = str_replace( 'http://', "$scheme://", $url );
        }

        $ignore_caller = $this->ignore_rewrite_caller();

        if ( !empty( $path ) && is_string( $path ) && strpos( $path, '..' ) === false ) {
            $url .= '/' . ltrim( $path, '/' );
        }

        if ( !$ignore_caller ) {
            $url = call_user_func($this->get_plugin_prefix() . 'convertURL', $url, $this->get_lang(), true);
        }

        return $url;
    }
    
    
    
    /**
     * Filter that changes the permastruct depending
     * 
     * @param string $permastruct default permastruct given b wp_rewrite
     * @param string $name the name of the extra permastruct
     * @return string processed permastruct
     *
     * @since 1.0
     */
    public function get_extra_permastruct( $permastruct = false, $name = false ) {
        
        if ( !$name || !$permastruct ) {
            return '';
        }
        
        if ( $base = $this->get_base_slug($name, $this->get_lang()) ) {
            return "/$base/%$name%";
        }
        
        return $permastruct;
    }
        
    
    
    /**
     * Filter that translates the slug parts in a page link
     * 
     * @param $link the link for the page generated by Wordpress
     * @param $id the id of the page
     * @return the link translated
     *
     * @since 1.0
     */
    public function post_type_link( $link, $post, $leavename, $sample ) {
        global $wp_rewrite;

        if ( is_wp_error( $post ) ) {
            return $post;
        }

        $post_link = apply_filters( 'qts_permastruct', $wp_rewrite->get_extra_permastruct($post->post_type), $post->post_type);
        
        $slug = get_post_meta( $post->ID, $this->get_meta_key(), true );
        if (!$slug) {
            $slug =  $post->post_name;
        }

        $draft_or_pending = isset($post->post_status) && in_array( $post->post_status, array( 'draft', 'pending', 'auto-draft' ) );

        $post_type = get_post_type_object($post->post_type);

        if ( !empty($post_link) && ( !$draft_or_pending || $sample ) ) {
            if ( ! $leavename ) {
                if ( $post_type->hierarchical )
                    $slug = $this->get_page_uri($post->ID);
                $post_link = str_replace("%$post->post_type%", $slug, $post_link);
            }
            
            $post_link = home_url( user_trailingslashit($post_link) );
            
        } else {
            
            if ( $post_type->query_var && ( isset($post->post_status) && !$draft_or_pending ) ) {
                $post_link = add_query_arg($post_type->query_var, $slug, '');
            } else {
                $post_link = add_query_arg(array('post_type' => $post->post_type, 'p' => $post->ID), '');
            }
            
            $post_link = home_url($post_link);
        }

        return $post_link;
    }
    
    
    
    /**
     * Filter that translates the slug in a post link
     * 
     * @param $link the link generated by wordpress
     * @param $post the post data
     * @param $leavename parameter used by get_permalink. Whether to keep post name or page name. 
     * @return the link translated
     *
     * @since 1.0
     */
    public function post_link( $link, $post, $leavename ) {
        global $q_config;
        
        $rewritecode = array(
            '%year%',
            '%monthnum%',
            '%day%',
            '%hour%',
            '%minute%',
            '%second%',
            $leavename? '' : '%postname%',
            '%post_id%',
            '%category%',
            '%author%',
            $leavename? '' : '%pagename%',
        );

        if ( empty($post->ID) ) {
            return false;
        }

        $permalink = $this->permalink_structure;

        if ( '' != $permalink && !in_array($post->post_status, array('draft', 'pending', 'auto-draft')) ) {
            $unixtime = strtotime($post->post_date);
            
            $category = '';
            if ( strpos($permalink, '%category%') !== false ) {
                $cats = get_the_category($post->ID);
                if ( $cats ) {
                    usort($cats, '_usort_terms_by_ID'); // order by ID
                    
                    $category = get_term_meta($cats[0]->term_id, $this->get_meta_key(), true );
                    if (!$category) $category = $cats[0]->slug;
                    
                    if ( $parent = $cats[0]->parent )
                        $category = $this->get_category_parents($parent, false, '/', true) . $category;
                }
                // show default category in permalinks, without
                // having to assign it explicitly
                if ( empty($category) ) {
                    $default_category = get_category( get_option( 'default_category' ) );
                    
                    $default_category_slug = get_term_meta($default_category->term_id, $this->get_meta_key(), true );
                    if (!$default_category_slug) $default_category_slug = $default_category->slug;
                    
                    $category = is_wp_error( $default_category ) ? '' : $default_category_slug;
                }
            }

            $author = '';
            if ( strpos($permalink, '%author%') !== false ) {
                $authordata = get_userdata($post->post_author);
                $author = $authordata->user_nicename;
            }

            $date = explode(" ",date('Y m d H i s', $unixtime));
            
            $post_slug = get_post_meta($post->ID, $this->get_meta_key(), true );
            if (!$post_slug) {
                $post_slug = $post->post_name;
            }
            
            $rewritereplace =
            array(
                $date[0],
                $date[1],
                $date[2],
                $date[3],
                $date[4],
                $date[5],
                $post_slug,
                $post->ID,
                $category,
                $author,
                $post_slug,
            );
            $permalink = home_url( str_replace($rewritecode, $rewritereplace, $permalink));
            if ($q_config['url_mode'] != 1) {
                $permalink = user_trailingslashit($permalink, 'single');
            }
        } else { // if they're not using the fancy permalink option
            $permalink = home_url('?p=' . $post->ID);
        }
        
        return $permalink;
    }
    
    
    
    /**
     * Retrieve category parents with separator.
     *
     * @param int $id Category ID.
     * @param bool $link Optional, default is false. Whether to format with link.
     * @param string $separator Optional, default is '/'. How to separate categories.
     * @param bool $nicename Optional, default is false. Whether to use nice name for display.
     * @param array $visited Optional. Already linked to categories to prevent duplicates.
     * @return string
     *
     * @since 1.0
     */
    private function get_category_parents( $id, $link = false, $separator = '/', $nicename = false, $visited = array() ) {
        
        $chain = '';
        if(phpversion() >= 5.4) {
            $parent = get_category( $id );
        } else {
            $parent = &get_category( $id );
        }

        if ( is_wp_error( $parent ) ) {
            return $parent;
        }

        if ( $nicename ) {

            $name = get_term_meta($parent->term_id, $this->get_meta_key(), true );
            if (!$name) {
                $name = $parent->slug;
            }
        } else {
            $name = $parent->name;
        }

        if ( $parent->parent && ( $parent->parent != $parent->term_id ) && !in_array( $parent->parent, $visited ) ) {
            $visited[] = $parent->parent;
            $chain .= $this->get_category_parents( $parent->parent, $link, $separator, $nicename, $visited );
        }
        
        if ( $link ) {
            $chain .= '<a href="' . get_category_link( $parent->term_id ) . '" title="' . esc_attr( sprintf( __( "View all posts in %s", "qts" ), $parent->name ) ) . '">'.$name.'</a>' . $separator;
        } else {
            $chain .= $name.$separator;
        }
        
        return $chain;
    }
    

    
    
    
    /**
     * Filter that translates the slug parts in a page link
     * 
     * @param $link the link for the page generated by Wordpress
     * @param $id the id of the page
     * @return the link translated
     *
     * @since 1.0
     */
    public function _get_page_link( $link, $id ) {
        global $post, $wp_rewrite, $q_config;

        $current_post = $post;

        if ( !$id ) {
            $id = (int) $post->ID;
        } else {
            if(phpversion() >= 5.4) {
                $current_post = get_post($id);
            } else {
                $current_post = &get_post($id);
            }
        }

        $draft_or_pending = in_array( $current_post->post_status, array( 'draft', 'pending', 'auto-draft' ) );

        $link = $wp_rewrite->get_page_permastruct();

        if ( !empty($link) && ( isset($current_post->post_status) && !$draft_or_pending ) ) {
            
            $link = str_replace('%pagename%', $this->get_page_uri($id), $link);
            
            $link = trim($link, '/'); // hack
            $link = home_url("/$link/"); // hack
            
            if ($q_config['url_mode'] != 1)
                $link = user_trailingslashit($link, 'page');
            
        } else {
            
            $link = home_url("?page_id=$id");
        }

        return $link;
    }
    
    
    
    /**
     * Builds URI for a page.
     *
     * Sub pages will be in the "directory" under the parent page post name.
     *
     * @param mixed $page Page object or page ID.
     * @return string Page URI.
     *
     * @since 1.0
     */
    private function get_page_uri($page) {
        
        if ( ! is_object($page) ) {
            $page = get_post($page);
        }
        
        $uri = get_post_meta( $page->ID, $this->get_meta_key(), true );
        if (!$uri) {
            $uri =  $page->post_name;
        }

        // A page cannot be it's own parent.
        if ( $page->post_parent == $page->ID ) {
            return $uri;
        }

        while ($page->post_parent != 0) {
            $page = get_post($page->post_parent);
            
            $page_name = get_post_meta( $page->ID, $this->get_meta_key(), true );
            if (!$page_name) {
                $page_name = $page->post_name;
            }
            
            $uri = $page_name . "/" . $uri;
        }

        return $uri;
    }
    
    
    
    /**
     * Filter that translates the slug parts in a term link
     * 
     * @param $link the link for the page generated by Wordpress
     * @param $term object
     * @param $taxonomy object
     * @return the link translated
     *
     * @since 1.0
     */
    public function term_link( $link, $term, $taxonomy ) {
        global $wp_rewrite;
        
        // parse normal term names for ?tag=tagname
        if (empty($this->permalink_structure)) return $link;

        if ( !is_object($term) ) {
            if ( is_int($term) ) {
                $term = &get_term($term, $taxonomy);
            } else {
                $term = $this->get_term_by('slug', $term, $taxonomy);
            }
        }

        if ( !is_object($term) ) {
            $term = new WP_Error('invalid_term', __('Empty Term', 'qts'));
        }

        if ( is_wp_error( $term ) ) {
            return $term;
        }

        $taxonomy = $term->taxonomy;

        $termlink = apply_filters( 'qts_permastruct', $wp_rewrite->get_extra_permastruct($taxonomy), $taxonomy);
        
        $slug = get_term_meta( $term->term_id, $this->get_meta_key(), true );
        if (!$slug) {
            $slug = $term->slug;
        }
        
        $t = get_taxonomy($taxonomy);

        if ( empty($termlink) ) {
            if ( 'category' == $taxonomy )
                $termlink = '?cat=' . $term->term_id;
            elseif ( $t->query_var )
                $termlink = "?$t->query_var=$slug";
            else
                $termlink = "?taxonomy=$taxonomy&term=$slug";
            $termlink = home_url($termlink);
        } else {
            if ( $t->rewrite['hierarchical'] ) {
                $hierarchical_slugs = array();
                $ancestors = get_ancestors($term->term_id, $taxonomy);
                foreach ( (array)$ancestors as $ancestor ) {
                    $ancestor_term = get_term($ancestor, $taxonomy);
                    
                    $ancestor_slug = get_term_meta( $ancestor_term->term_id, $this->get_meta_key(), true );
                    if (!$ancestor_slug) $ancestor_slug = $ancestor_term->slug;
                    
                    $hierarchical_slugs[] = $ancestor_slug;
                }
                $hierarchical_slugs = array_reverse($hierarchical_slugs);
                $hierarchical_slugs[] = $slug;
                $termlink = str_replace("%$taxonomy%", implode('/', $hierarchical_slugs), $termlink);
            } else {
                $termlink = str_replace("%$taxonomy%", $slug, $termlink);
            }
            $termlink = home_url( user_trailingslashit($termlink, 'category') );
        }
        return $termlink;
    }
    
    
    
    /**
     * Get all Term data from database by Term field and data.
     *
     * @param (string) $field Either 'slug', 'name', or 'id'
     * @param (string|int) $value Search for this term value
     * @param (string) $taxonomy Taxonomy Name
     * @param (string) $output Constant OBJECT, ARRAY_A, or ARRAY_N
     * @param (string) $filter Optional, default is raw or no WordPress defined filter will applied.
     * @return (mixed) Term Row from database. Will return false if $taxonomy does not exist or $term was not found.
     *
     * @since 1.0
     */
    private function get_term_by($field, $value, $taxonomy, $output = OBJECT, $filter = 'raw') {
        global $wpdb;
        
        $original_field = $field;

        if ( ! taxonomy_exists($taxonomy) ) {
            return false;
        }

        if ( 'slug' == $field ) {
            $field = 'm.meta_key = \''.$this->get_meta_key().'\' AND m.meta_value';
            $value = sanitize_title($value);
            if ( empty($value) )
                return false;
        } else if ( 'name' == $field ) {
            // Assume already escaped
            $value = stripslashes($value);
            $field = 't.name';
        } else {
            $term = get_term( (int) $value, $taxonomy, $output, $filter);
            if ( is_wp_error( $term ) )
                $term = false;
            return $term;
        }
        
        $term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t, $wpdb->term_taxonomy AS tt, $wpdb->termmeta AS m WHERE t.term_id = tt.term_id AND tt.term_id = m.term_id AND tt.taxonomy = %s AND $field = %s LIMIT 1", $taxonomy, $value) );

        if ( !$term && 'slug' == $original_field ) {
            $field = 't.slug';
            $term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND $field = %s LIMIT 1", $taxonomy, $value) );
        }
        
        if ( !$term ) {
            return false;
        }

        wp_cache_add($term->term_id, $term, $taxonomy);

        $term = apply_filters('get_term', $term, $taxonomy);
        $term = apply_filters("get_$taxonomy", $term, $taxonomy);
        $term = sanitize_term($term, $taxonomy, $filter);

        if ( $output == OBJECT ) {
            return $term;
        } elseif ( $output == ARRAY_A ) {
            return get_object_vars($term);
        } elseif ( $output == ARRAY_N ) {
            return array_values(get_object_vars($term));
        } else {
            return $term;
        }
    }



    /**
     * Fix for:
     * - Taxonomy names in Taxonomy Manage page
     * - 'Popular Tags' in Taxonomy (Tags) Manage page
     * - Category filter dropdown menu in Post Manage page
     * - Category list in Post Edit page
     * - 'Most Used' tags list in Post Edit page (but have issues when saving)
     * 
     * @param (array) $terms
     * @param (string|array) $taxonomy
     * @since 1.2
     */
    function get_terms($terms, $taxonomy) {
        
        global $pagenow;
        
        
        if ( $pagenow != 'admin-ajax.php' ) {
            
            $meta = get_option('qtranslate_term_name');
            $lang = call_user_func($this->get_plugin_prefix() . 'getLanguage');
                    
            
            if ( !empty( $terms ) ) {
                foreach ($terms as $term_index => $term) {
                    // after saving, dont do anything
                    if( ( isset($_POST['action'] ) && $_POST['action']  == "editedtag") ||
                     !is_object( $term ) ) {
                        return $terms;
                    }
                    $termname = $term->name;
					if( isset( $meta[$termname][$lang] ) ) {
                        $term->name = $meta[$termname][$lang];
                    }
                };
            };
        }
        return $terms;
    }



    /**
     * Fix for:
     * - Taxonomy & custom taxonomy names in Post Manage page
     * - List of tags already added to the post in Post 
     * - Edit page (but have issues when saving)
     *
     * @param (array) $terms
     * @param (int|array) $obj_id
     * @param (string|array) $taxonomy
     * @param (array) $taxonomy
     * @since 1.2
     */ 
    function get_object_terms($terms, $obj_id, $taxonomy, $args) {
        
        global $pagenow;
        
        // Although in post edit page the tags are translated,
        // but when saving/updating the post Wordpress considers
        // the translated tags as new tags. Due to this
        // issue I limit this 'hack' to the post manage
        // page only.
        if ( $pagenow == 'edit.php' ) {
            
            // $taxonomy output seems to be wrapped
            // in single quotes, thus remove them to
            // make the output valid
            $tax = str_replace("'", "", $taxonomy);
            
            $meta = get_option('qtranslate_term_name');
            $lang = call_user_func($this->get_plugin_prefix() . 'getLanguage');
            
            if ( !empty( $terms ) ) {
                foreach ($terms as $term) {
                    if( isset( $meta[$term->name][$lang] ) ) {
                        $term->name = $meta[$term->name][$lang];
                    }
                };
            };
        
        }
        return $terms;
    }



    /**
     * hide quickedit slug
     * 
     * @since 1.0
     */
    public function hide_quick_edit() {
        echo "<!-- QTS remove quick edit box -->" . PHP_EOL;
        echo "<style type=\"text/css\" media=\"screen\">" . PHP_EOL;
        echo "  .inline-edit-row fieldset.inline-edit-col-left .inline-edit-col *:first-child + label + label  { display: none !important }" . PHP_EOL;
        echo "</style>" . PHP_EOL;
    }
    
    
    
    /**
     * Hide auttomatically the wordpress slug blog in edit posts page
     *
     * @since 1.0
     */
    public function hide_slug_box() {
        global $pagenow;
        
        switch ( $pagenow ):
            case 'edit-tags.php':
            
                echo "<!-- QTS remove slug box -->" . PHP_EOL;
                echo "<script type=\"text/javascript\" charset=\"utf-8\">" . PHP_EOL;
                echo "  jQuery(document).ready(function($){" . PHP_EOL;
                echo "      $(\"#tag-slug\").parent().hide();" . PHP_EOL;
                echo "      $(\".form-field td #slug\").parent().parent().hide();" . PHP_EOL;
                echo "  });" . PHP_EOL;
                echo "</script>" . PHP_EOL;
                break;
            
            case 'post.php':
            
                echo "<!-- QTS remove slug box -->" . PHP_EOL;
                echo "<style type=\"text/css\" media=\"screen\">" . PHP_EOL;
                echo "  #edit-slug-box { display: none !important}" . PHP_EOL;
                echo "</style>" . PHP_EOL;
                break;
        endswitch;
    }
    
    
        
    /**
     * Creates a metabox for every post, page and post type avaiable
     *
     * @since 1.0
     */
    public function add_slug_meta_box() {
        
        if ( function_exists( 'add_meta_box' ) ) {
            
            $context  = apply_filters("qts_admin_meta_box_context","side");
            $priority = apply_filters("qts_admin_meta_box_priority","high");

            add_meta_box( 'qts_sectionid', __('Slug', 'qts'), array(&$this, 'draw_meta_box'), 'post', $context, $priority);
            add_meta_box( 'qts_sectionid', __('Slug', 'qts'), array(&$this, 'draw_meta_box'), 'page', $context, $priority);
            
            foreach ( get_post_types( array('_builtin' => false ) ) as $ptype )
                add_meta_box( 'qts_sectionid', __('Slug', 'qts'), array(&$this, 'draw_meta_box'), $ptype, $context, $priority );
        }
    }
    
    
    
    /**
     * Shows the fields where insert the translated slugs in the post and page edit form.
     *
     * @param $post (object) current post object
     *
     * @since 1.0
     */
    public function draw_meta_box( $post ) {
        global $q_config;
      
        // Use nonce for verification
        echo "<table style=\"width:100%\">" . PHP_EOL;
        echo "<input type=\"hidden\" name=\"qts_nonce\" id=\"qts_nonce\" value=\"" . wp_create_nonce( 'qts_nonce' ) . "\" />" . PHP_EOL;
  
        foreach ($q_config['enabled_languages'] as $lang):
            
            $slug = get_post_meta( $post->ID, $this->get_meta_key($lang), true);
            
            $value = ( $slug ) ? htmlspecialchars( $slug , ENT_QUOTES ) : '';
            
            echo "<tr>" . PHP_EOL;
            echo "<th style=\"text-align:left; width:10%; color:#555 \"><label for=\"qts_{$lang}_slug\">".__($q_config['language_name'][$lang], 'qtranslate')."</label></th>" . PHP_EOL;
            echo "<td><input type=\"text\" id=\"qts_{$lang}_slug\" name=\"qts_{$lang}_slug\" value=\"$value\" style=\"width:90%; margin-left:10%; color:#777\" /></td>" . PHP_EOL;
            echo "</tr>" . PHP_EOL;
            
        endforeach;
        
        echo '</table>' . PHP_EOL;
    }
    
    
    
    /**
     * Sanitize title as slug, if empty slug
     * 
     * @param $post (object) the post object
     * @param $slug (string) the slug name
     * @param $lang (string) the language
     * @return the slug validated
     *
     * @since 1.0
     */
    public function validate_post_slug( $slug, $post, $lang ) { 
            
        $post_title = trim(call_user_func($this->get_plugin_prefix() . 'use',$lang, $_POST['post_title']));
        $post_name = get_post_meta($post->ID, $this->get_meta_key($lang), true);
        if (!$post_name) {
            $post_name = $post->post_name;
        }
        
        $name = ( $post_title == '' || strlen($post_title) == 0 ) ? $post_name : $post_title;
        
        $slug = trim($slug);
            
        $slug = (empty($slug)) ? sanitize_title($name) : sanitize_title($slug);
        
        
        
        return htmlspecialchars( $slug , ENT_QUOTES );
    }
    
    
    
    /**
     * Validates post slug against repetitions per language
     * 
     * @param $post (object) the post object
     * @param $slug (string) the slug name
     * @param $lang (string) the language
     * @return the slug validated
     *
     * @since 1.0
     */
    public function unique_post_slug( $slug, $post, $lang ) {
        
        $original_status = $post->post_status;
        
        if ( in_array($post->post_status, array('draft', 'pending')) ) {
            $post->post_status = 'publish';
        }
        
        $slug = $this->wp_unique_post_slug( $slug, $post->ID, $post->post_status, $post->post_type, $post->post_parent, $lang );
        
        $post->post_status = $original_status;
        
        return $slug;
    }
    
    
    
    /**
     * Computes a unique slug for the post and language, when given the desired slug and some post details.
     *
     * @param string $slug the desired slug (post_name)
     * @param integer $post_ID
     * @param string $post_status no uniqueness checks are made if the post is still draft or pending
     * @param string $post_type
     * @param integer $post_parent
     * @return string unique slug for the post, based on language meta_value (with a -1, -2, etc. suffix)
     *
     * @since 1.0
     */
    public function wp_unique_post_slug( $slug, $post_ID, $post_status, $post_type, $post_parent, $lang ) {
        if ( in_array( $post_status, array( 'draft', 'pending', 'auto-draft' ) ) ) {
            return $slug;
        }

        global $wpdb, $wp_rewrite;

        $feeds = $wp_rewrite->feeds;
        if ( ! is_array( $feeds ) ) {
            $feeds = array();
        }
        
        $meta_key = $this->get_meta_key($lang);
        if ( 'attachment' == $post_type ) {
            // Attachment slugs must be unique across all types.
            $check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND ID != %d LIMIT 1";
            $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_ID ) );

            if ( $post_name_check || in_array( $slug, $feeds ) || apply_filters( 'wp_unique_post_slug_is_bad_attachment_slug', false, $slug ) ) {
                $suffix = 2;
                do {
                    $alt_post_name = substr ($slug, 0, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
                    $post_name_check = $wpdb->get_var( $wpdb->prepare($check_sql, $alt_post_name, $post_ID ) );
                    $suffix++;
                } while ( $post_name_check );
                $slug = $alt_post_name;
            }
        } else {
            // Post slugs must be unique across all posts.
            $check_sql = "SELECT $wpdb->postmeta.meta_value FROM $wpdb->posts,$wpdb->postmeta WHERE $wpdb->posts.ID = $wpdb->postmeta.post_id AND $wpdb->postmeta.meta_key = '%s' AND $wpdb->postmeta.meta_value = '%s' AND $wpdb->posts.post_type = %s AND ID != %d LIMIT 1";
            $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $meta_key, $slug, $post_type, $post_ID ) );

            if ( $post_name_check || in_array( $slug, $feeds ) || apply_filters( 'wp_unique_post_slug_is_bad_flat_slug', false, $slug, $post_type ) ) {
                $suffix = 2;
                do {
                    $alt_post_name = substr( $slug, 0, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
                    $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $meta_key, $alt_post_name, $post_type, $post_ID ) );
                    $suffix++;
                } while ( $post_name_check );
                $slug = $alt_post_name;
            }
        }

        return $slug;
    }
    
    
    
    
    /**
     * Saves the translated slug when the page is saved
     * 
     * @param $post_id the post id
     * @param $post the post object
     *
     * @since 1.0
     */
    public function save_postdata( $post_id, $post ) {
        
        $post_type_object = get_post_type_object( $post->post_type);
        
        
        if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)                       // check autosave
        || (!isset($_POST['post_ID']) || $post_id != $_POST['post_ID']) // check revision
        || (!wp_verify_nonce( $_POST['qts_nonce'], 'qts_nonce'))                // verify nonce
        || (!current_user_can($post_type_object->cap->edit_post, $post_id))) {  // check permission
            return $post_id;
        }
        foreach ($this->get_enabled_languages() as $lang) {
            
            $meta_name = $this->get_meta_key($lang);
            $meta_value = apply_filters( 'qts_validate_post_slug', $_POST["qts_{$lang}_slug"], $post, $lang);
            delete_post_meta($post_id, $meta_name);
            update_post_meta($post_id, $meta_name, $meta_value);
            
        }
    }
    
    
    
    /**
     * Display multiple input fields, one per language
     * 
     * @param $term the term object
     *
     * @since 1.0
     */
    public function show_term_fields( $term ) {
        global $q_config;
        
        // prints the fields in edit page
        if (isset($_GET['action']) && $_GET['action'] == 'edit' ):
  
            echo "<table class=\"form-table\">" . PHP_EOL;
            echo "<input type=\"hidden\" name=\"qts_nonce\" id=\"qts_nonce\" value=\"" .  wp_create_nonce( 'qts_nonce' ) . "\" />" . PHP_EOL;
  
            foreach( $q_config['enabled_languages'] as $lang ) {
            
                $slug = (is_object($term)) ? get_term_meta( $term->term_id, $this->get_meta_key($lang), true ) : '';
            
                $value = ( $slug ) ? htmlspecialchars( $slug , ENT_QUOTES ) : '';
            
                echo "<tr class=\"form-field form-required\">" . PHP_EOL;
                echo "<th scope=\"row\" valig=\"top\"><label for=\"qts_{$lang}_slug\">".sprintf( __('Slug (%s)', 'qts'), $q_config['language_name'][$lang] )."</label></th>" . PHP_EOL;
                echo "<td><input type=\"text\" name=\"qts_{$lang}_slug\" value=\"$value\" /></td></tr>" . PHP_EOL;
            
            }
        
            echo '</table>';
        
        // prints the fields in new page
        else:
            echo "<input type=\"hidden\" name=\"qts_nonce\" id=\"qts_nonce\" value=\"" .  wp_create_nonce( 'qts_nonce' ) . "\" />" . PHP_EOL;
  
            foreach( $q_config['enabled_languages'] as $lang ) {
                
                echo "<div class=\"form-field\">" . PHP_EOL;
            
                $slug = (is_object($term)) ? get_term_meta( $term->term_id, $this->get_meta_key($lang), true ) : '';
            
                $value = ( $slug ) ? htmlspecialchars( $slug , ENT_QUOTES ) : '';
            
                echo "<label for=\"qts_{$lang}_slug\">".sprintf( __('Slug (%s)', 'qts'), $q_config['language_name'][$lang] )."</label>" . PHP_EOL;
                echo "<input type=\"text\" name=\"qts_{$lang}_slug\" value=\"$value\" aria-required=\"true\">" . PHP_EOL;
                
                echo '</div>';
            
            }

        endif;
    }
    
    
    
    /**
     * Sanitize title as slug, if empty slug
     * 
     * @param $term (object) the term object
     * @param $slug (string) the slug name
     * @param $lang (string) the language
     * @return the slug validated
     *
     * @since 1.0
     */
    public function validate_term_slug( $slug, $term, $lang ) {

        global $q_config;
        
        $lang_name = $q_config['term_name'][$term->name][$lang];
        
        $ajax_name = 'new' . $term->taxonomy;
        
        $post_name = isset($_POST['name']) ? $_POST['name'] : '';
        
        $term_name = isset($_POST[$ajax_name]) ? trim($_POST[$ajax_name]) : $post_name;
    
        if (empty($term_name)) {
            return $slug;
        }
        
        $name = ( $lang_name == '' || strlen($lang_name) == 0 ) ? $term_name : $lang_name;
        
        $slug = trim($slug);
            
        $slug = (empty($slug)) ? sanitize_title($name) : sanitize_title($slug);
        
        return htmlspecialchars( $slug , ENT_QUOTES );
    }
    
    
    
    /**
     * Will make slug unique per language, if it isn't already.
     *
     * @param string $slug The string that will be tried for a unique slug
     * @param object $term The term object that the $slug will belong too
     * @param object $lang The language reference 
     * @return string Will return a true unique slug.
     *
     * @since 1.0
     */
    public function unique_term_slug($slug, $term, $lang) {
      
        global $wpdb;
		
        $meta_key_name = $this->get_meta_key($lang);
        $query = $wpdb->prepare("SELECT term_id FROM $wpdb->termmeta WHERE meta_key = '%s' AND meta_value = '%s' AND term_id != %d ", $meta_key_name, $slug, $term->term_id);
        $exists_slug = $wpdb->get_results($query);

        if ( empty($exists_slug) ) {
            return $slug;
        }
        
        // If we didn't get a unique slug, try appending a number to make it unique.
        $query = $wpdb->prepare("SELECT meta_value FROM $wpdb->termmeta WHERE meta_key = '%s' AND meta_value = '%s' AND term_id != %d", $meta_key_name, $slug, $term->term_id);

        if ( $wpdb->get_var( $query ) ) {
          $num = 2;
          do {
            $alt_slug = $slug . "-$num";
            $num++;
            $slug_check = $wpdb->get_var(
              $wpdb->prepare(
               "SELECT meta_value FROM $wpdb->termmeta WHERE meta_key = '%s' AND meta_value = '%s'",
               $meta_key_name,
               $alt_slug) );
          } while ( $slug_check );
          $slug = $alt_slug;
        }

        return $slug;
    }
    
    
    
    /**
     * Display multiple input fields, one per language
     * 
     * @param $term_id the term id
     * @param $tt_id the term taxonomy id
     * @param $taxonomy the term object
     *
     * @since 1.0
     */
    public function save_term( $term_id, $tt_id, $taxonomy ) {
        
        $cur_screen = get_current_screen();
        if ( (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE )  // check autosave
        || ( !current_user_can('edit_posts') ) // check permission
        || ( isset($cur_screen) && $cur_screen->id === "nav-menus") 
        ) {                  
            return $term_id;
        }
        
        $term = get_term( $term_id, $taxonomy);
        foreach( $this->get_enabled_languages() as $lang ) {
            $meta_name = $this->get_meta_key($lang);
      
            //43LC: when at the post edit screen and creating a new tag
            // the $slug comes from $_POST with the value of the post slug,
            // not with the term slug. 
            if ($_POST['action'] == "editpost")  {
                // so we use the slug wp gave it
                $term_slug = $term->slug;
            } else {
                // otherwise, its the edit term screen
                $term_slug =  $_POST["qts_{$lang}_slug"];
            }
            
            $meta_value = apply_filters( 'qts_validate_term_slug', $term_slug, $term, $lang);
                
            delete_term_meta($term_id, $meta_name);
            update_term_meta($term_id, $meta_name, $meta_value);
       }
    }
    
    
    
    /**
     * deletes termmeta rows associated with the term
     * 
     * @since 1.0
     */ 
    public function delete_term($term_id, $tt_id, $taxonomy) {
        global $wpdb;
        
        $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->termmeta WHERE term_id = %d", $term_id ) );
    }
    
    
    
    /**
	 * creates and prints the forms and hides the default fields 
	 * @param object $term the term object 
	 * @since 1.1.12
	 * 
	 * TODO: merge with our own form.
	 * TODO: move code into js file
	 *
	 */
	public function qts_modify_term_form($term) {
		echo "<script type=\"text/javascript\">\n// <![CDATA[\r\n";
		if(is_object($term)&&isset($term->name)) {
			$termname = $term->name;
		} else {
			$termname = "";
		}
	    if(isset($_GET['action']) && $_GET['action']=='edit') {
		   foreach($this->get_enabled_languages() as $language) {
			   echo $this->qts_insert_term_input('name', __('Name','qts'), $termname, $language,"edit");
	        }
	    } else {
		   foreach($this->get_enabled_languages() as $language) {
	           echo $this->qts_insert_term_input('tag-name', __('Name','qts'), $termname, $language,"new");   
	        }
	    }
		// hide real category text
		echo "if (ins != null) ins.style.display='none';\n";
		echo "// ]]>\n</script>\n";
	}

	/**
	 * Helper for qts_modify_term_form_for
	 * @param string $id the term id
	 * @param object #term the term
	 * @param string $language the term name
	 * @param string $action the term name
	 * @return string $html the new input fields
	 * @since 1.1.12
	 * TODO: use DocumentFragment
	 */
	private function qts_insert_term_input($id,$name, $language,$action){
		global $q_config;
		$html = "";
		if( $action === "new") {
		    $html ="
	        var il = document.getElementsByTagName('input'),
	        	 d = document.createElement('div'),
                 l = document.createTextNode('".$name." (".$q_config['language_name'][$language].")'),
	            ll = document.createElement('label'),
	             i = document.createElement('input'),
	           ins = null;
	        for(var j = 0; j < il.length; j++) {
	            if(il[j].id=='".$id."') {
	                ins = il[j];
	                break;
	            }
	        }
	        i.type = 'text';
	        i.id = i.name = ll.htmlFor ='qtrans_term_".$language."';
	    ";
		} elseif ( $action === "edit") {
		    $html ="
	        var tr = document.createElement('tr'),
	            th = document.createElement('th'),
	            ll = document.createElement('label'),
	             l = document.createTextNode('".$name." (".$q_config['language_name'][$language].")'),
	            td = document.createElement('td'),
	             i = document.createElement('input'),
	           ins = document.getElementById('".$id."');
	        i.type = 'text';
	        i.id = i.name = ll.htmlFor ='qtrans_term_".$language."';
	    ";
	    }
		if(isset($q_config['term_name'][$termname][$language])) {
  		 $html .="
		     i.value = '".addslashes(htmlspecialchars_decode($q_config['term_name'][$termname][$language], ENT_QUOTES))."';";
		     //43LC: applied ENT_QUOTES to both edit and new forms. 
		} else {
		  $html .="
			  if (ins != null)
				  i.value = ins.value;
			  ";
		}
		
		if($language == $this->default_language) {
			$html .="
				i.onchange = function() { 
					var il = document.getElementsByTagName('input'),
					   ins = null;
					for(var j = 0; j < il.length; j++) {
						if(il[j].id=='".$id."') {
							ins = il[j];
							break;
						}
					}
					if (ins != null)
						ins.value = document.getElementById('qtrans_term_".$language."').value;
				};
				";
		}
		if( $action === "new") {
	        $html .="
	        if (ins != null)
	            ins = ins.parentNode;
	        d.className = 'form-field form-required';
	        ll.appendChild(l);
	        d.appendChild(ll);
	        d.appendChild(i);
	        if (ins != null)
	            ins.parentNode.insertBefore(d,ins);
	        ";
	    } elseif ( $action === "edit") {
	        $html .="
	        ins = ins.parentNode.parentNode;
	        tr.className = 'form-field form-required';
	        th.scope = 'row';
	        th.vAlign = 'top';
	        ll.appendChild(l);
	        th.appendChild(ll);
	        tr.appendChild(th);
	        td.appendChild(i);
	        tr.appendChild(td);
	        ins.parentNode.insertBefore(tr,ins);
	        ";
	    }
		return $html;	
	}
    /**
     * adds support for qtranslate in taxonomies
     *
     * @since 1.0
     */
    public function taxonomies_hooks() {
    
        $taxonomies = $this->get_public_taxonomies();

        if ($taxonomies) {
            foreach ($taxonomies  as $taxonomy ) {
                add_action( $taxonomy->name.'_add_form', array(&$this, 'qts_modify_term_form'));
                add_action( $taxonomy->name.'_edit_form', array(&$this, 'qts_modify_term_form'));
                add_action( $taxonomy->name.'_add_form',  array(&$this, 'show_term_fields'));
                add_action( $taxonomy->name.'_edit_form_fields', array(&$this, 'show_term_fields') );
                add_filter('manage_edit-'.$taxonomy->name.'_columns', array(&$this, 'taxonomy_columns'));
                add_filter('manage_'.$taxonomy->name.'_custom_column', array(&$this, 'taxonomy_custom_column'), 0, 3);
            }
        }
    }
    
    
    
    /*
     * Bug fix for slug column in taxonomies
     * 
     * @since 1.0
     */
    public function taxonomy_columns($columns) {
        unset($columns['slug']);
        unset($columns['posts']);
        
        $columns['qts-slug'] = __('Slug', 'qts');
        $columns['posts'] = __('Posts', 'qts');
        
        return $columns;
    }
    
    
    
    /*
     * Bug fix for slug column in taxonomies
     * 
     * @since 1.0
     */
    public function taxonomy_custom_column($str, $column_name, $term_id) {
        
        switch ($column_name) {
            case 'qts-slug':
                echo get_term_meta($term_id, $this->get_meta_key(), true);
                break;
        }
        return false;
    }
    
    
    
    
    /**
     * Bug fix for multisite blog names
     * 
     * @since 1.0
     */
    public function blog_names($blogs) {
        
        foreach ($blogs as $blog) {
            $blog->blogname = __($blog->blogname);
        }
        
        return $blogs;
    }
    
    
    
    /**
     * Initialise the Language Widget selector
     * 
     * @since 1.0
     */
    public function widget_init() {
        
        if (class_exists('qTranslateWidget')) {
            unregister_widget('qTranslateWidget');
        }
        if (class_exists('mqTranslateWidget')) {
            unregister_widget('mqTranslateWidget');
        }
        if (class_exists('ppqTranslateWidget')) {
            unregister_widget('ppqTranslateWidget');
        }
        
        //if (class_exists('qTranslateXWidget')) {//it has additional features some people use.
        //    unregister_widget('qTranslateXWidget');
        //}
        
        register_widget('QtranslateSlugWidget');
    }
    
    
    
    /**
     * remove some default dashboard Widgets on Desktop
     *
     * @since 1.0
     */
    function remove_dashboard_widgets() {
        global $wp_meta_boxes;
        unset($wp_meta_boxes['dashboard']['side']['core']['dashboard_quick_press']);
    } 
    
    
    
    /**
     * adds support for qtranslate nav menus
     * 
     * @since 1.0
     */
    public function fix_nav_menu() {
        global $pagenow;
        
        if( $pagenow != 'nav-menus.php' ) {
            return;
        }
				//FIXME: fix the nav menu box
				//        wp_enqueue_script( 'nav-menu-query',  plugins_url( 'assets/js/qts-nav-menu-min.js' , dirname(__FILE__ ) ), 'nav-menu', '1.0' );
				//        add_meta_box( 'qt-languages', __('Languages', 'qts'), array(&$this, 'nav_menu_meta_box'), 'nav-menus', 'side', 'default' );
    }
    
    
    
    /**
     * draws meta box for select language
     * 
     * @since 1.0
     */
    public function nav_menu_meta_box() {
        global $q_config;
        echo '<p>';
        foreach($q_config['enabled_languages'] as $id => $language) {
            $checked = ($language == $q_config['language']) ? ' checked="checked"' : '';
            echo '<p style="margin:0 0 5px 0"><input type="radio" style="margin-right:5px" name="wa_qt_lang" value="' . $language . '" id="wa_gt_lang_' . $id . '" ' . $checked . '/>';
            echo '<label for="wa_gt_lang_' . $id . '">';
            echo '<img src="' . trailingslashit(WP_CONTENT_URL).$q_config['flag_location'].$q_config['flag'][$language] . '"/>&nbsp;';
            echo __($q_config['language_name'][$language], 'qtranslate');
            echo '</label></p>';
        }
         echo '<p style="margin:0 0 5px 0"><input type="radio" style="margin-right:5px" name="wa_qt_lang" value="all" id="wa_gt_lang_999" />';
            echo '<label for="wa_gt_lang_999">';
            echo __('All languages', 'qts');
            echo '</label></p>';
        echo '</p>';
    }
    
    
    
    /**
     * Language select function for templating
     *
     * @param $type (string) choose the type of menu: 'text', 'image', 'both', 'dropdown' 
     * @param $args (array) some args for draw the menu: array( 'id', 'class', 'short' );
     * 
     * @since 1.0
     */
    public function language_menu( $type = "text", $args = array() ) {
        global $q_config;
        

        // default arguments
        $defaults = array(
            'id' => "qts-lang-menu",
            'class' => "qts-lang-menu",
            'short' => false
        );
        $args = wp_parse_args( $args, $defaults );
        
        $languages = call_user_func($this->get_plugin_prefix() . 'getSortedLanguages');
        
        // every type
        switch ( $type ) {
            
            case 'image':
            case 'text':
            case 'both':
            
                $baseurl = dirname(plugins_url());
                $num_languages = count($languages);
                echo "<ul id=\"{$args['id']}\" class=\"qts_type_{$type} {$args['class']}\">". PHP_EOL;
                
                foreach( $languages as $index => $lang ):
                    
                    $url = $this->get_current_url($lang);
                    // 43LC: hack to play nice with qtranslate-x
                    if( "qtranxf_" === $this->plugin_prefix && $this->default_language === $lang ) {

                        $url = qtranxf_convertURL('',$lang,false,true);
                    }
                    $item_class = array();
                    if ( (string)$q_config['language'] == (string)$lang ) $item_class[] = 'current-menu-item';
                    if ( $index == ( $num_languages - 1) ) $item_class[] = 'last-child';
                    
          
                    $item_class = ' class="qts_lang_item ' . implode(' ', $item_class) . '"';
                    
                    $language_name = ($args['short']) ? $lang : $q_config['language_name'][$lang];
                    
                    if ( $type == 'image' ) {
                        $link_class = " class=\"qtrans_flag qtrans_flag_$lang\"";
                        $link_content = "<span style=\"display:none\">$language_name</span>";
                    } else if ( $type == 'both' ) {
                        $link_class = " class=\"qts_both qtrans_flag qtrans_flag_$lang\"";
                        $link_content = "$language_name";                        
                    } else {
                        $link_class = '';
                        $link_content = $language_name;
                        $link_flag ='';
                    }
                    if( $type == 'image' || $type == 'both' ) {
                        $link_flag_url =  $baseurl . '/'.$q_config['flag_location'].$q_config['flag'][$lang];
                        
                        //TODO: add i18n for alt attribute
                        //43LC: hardcoding height and width
                        $link_flag = "<img widht=\"18\" height=\"12\" src=\"$link_flag_url\" alt=\"$language_name\" />";
                    }

                    echo "<li $item_class><a href=\"$url\" lang=\"$lang\" hreflang=\"$lang\"$link_class>$link_flag$link_content</a></li>" . PHP_EOL;
                    
                endforeach;
                
                echo "</ul>". PHP_EOL;
                
                break;
                
            case 'dropdown':
            
                echo "<select id=\"{$args['id']}\" class=\"{$args['class']}\" onchange=\"window.location.href=this.options[this.selectedIndex].value\">". PHP_EOL;
                
                foreach( $languages as $index => $lang ):
                    
                    $url = $this->get_current_url($lang);
                    
                    $item_class = '';
                    if ( (string)$q_config['language'] == (string)$lang ) $item_class = 'selected="selected"';
                    
                    $language_name = ($args['short']) ? $lang : $q_config['language_name'][$lang];
                    
                    echo "<option value=\"$url\" $item_class>$language_name</option>" . PHP_EOL;
                    
                endforeach;
                
                echo "</select>". PHP_EOL;

                break;
        }
        
    }
}
<?php
/**
 * Define our settings sections
 *
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0
 * 
 * @return array key=$id, array value=$title in: add_settings_section( $id, $title, $callback, $page );
 */
function qts_options_page_sections() {
	
	$sections = array();
	$sections['post_types'] = __('Post types', 'qts');
	$sections['taxonomies'] = __('Taxonomies', 'qts');
	$sections['styles']     = __('Styles', 'qts');
	
	return $sections;	
}



/**
 * Helper for create arrays of choices
 *
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0
 *
 * @return array
 */
function get_multi_txt_choices($name = false) {
	global $q_config;
	
	if (!$name) return array();
	
	$choices = array();
	foreach( $q_config['enabled_languages'] as $key => $lang) {
		$label = sprintf( __('Slug (%s)', 'qts'), $q_config['language_name'][$lang] );
		$choices[] =  "$label|$lang"; // prints: 'Slug (English)|en' ( $name = books )
	}
	
	return $choices;
}



/**
 * Define our form fields (settings) for displaying the default styles
 *
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.1.7
 *
 * @return array
 */
function qts_options_page_styles() {
  
	  
    $options[] = array(
	    "section" => "styles",
	    "id"      => QTS_PREFIX . "styles",
	    "title"   => __('Change styles type', 'qts'),
	    "desc"    => array(
	    	__("adds a file (qts-default.css) to the theme's header.", "qts"),
	    	__("adds a minified ( slighlty faster) file (qts-default.min.css) to the theme's header.", "qts"),
	    	__("prints the styles directly into the theme's header.", "qts"),
	    	__("neither include not print the default style.", "qts")
	    	),
	    "type"    => "multi-radio",
	    'class'   => 'qts-style',
	    "choices" => array(
	    	__("file", "qts"),
	    	__("minified", "qts"),
	    	__("inline", "qts"),
	    	__("none", "qts")
	    	),
	    "std"     => "file"
  	);
  
	return $options;  
}



/**
 * Define our form fields (settings) 
 *
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0
 *
 * @return array
 */
function qts_options_page_fields() {
	
	$post_types = get_post_types( array('_builtin' => false, 'public' => true ), 'objects');
	
	// each post type
	foreach ($post_types as $post_type):
		
		$options[] = array(
			"section" => "post_types",
			"id"      => QTS_PREFIX . "post_type_" . $post_type->name,
			"title"   => $post_type->labels->singular_name,
			"desc"    => sprintf( __( '<code>http://example.org/<u>%s</u>/some-%s/</code>', 'qts' ), $post_type->name, $post_type->name),
			'class'	  => 'qts-slug',
			"type"    => "multi-text",
			"choices" => get_multi_txt_choices( $post_type->name),
			"std"     => ""
		);
		
	endforeach;
	// end each post type
	
	$options[] = array(
		"section" => "taxonomies",
		"id"      => QTS_PREFIX . "taxonomy_category",
		"title"   => __( 'Categories', 'qts' ),
		"desc"    => __( '<code>http://example.org/<u>category</u>/some-category/</code>', 'qts' ),
		"type"    => "multi-text",
		'class'	  => 'qts-slug',
		"choices" => get_multi_txt_choices('category'),
		"std"     => ""
	);
	
	$options[] = array(
		"section" => "taxonomies",
		"id"      => QTS_PREFIX . "taxonomy_post_tag",
		"title"   => __( 'Tags', 'qts' ),
		"desc"    => __( '<code>http://example.org/<u>tag</u>/some-tag/</code>', 'qts' ),
		"type"    => "multi-text",
		'class'	  => 'qts-slug',
		"choices" => get_multi_txt_choices('post_tag'),
		"std"     => ""
	);
	

	$taxonomies = get_taxonomies( array( 'public' => true, 'show_ui' => true, '_builtin' => false ), 'object' ); 
	
	// each extra taxonomy
	foreach ($taxonomies as $taxonomy):
		
		$options[] = array(
			"section" => "taxonomies",
			"id"      => QTS_PREFIX . "taxonomy_" . $taxonomy->name,
			"title"   => $taxonomy->labels->singular_name,
			"desc"    => sprintf( __( '<code>http://example.org/<u>%s</u>/some-%s/</code>', 'qts' ), $taxonomy->name, $taxonomy->name ),
			"type"    => "multi-text",
			'class'	  => 'qts-slug',
			"choices" => get_multi_txt_choices( $taxonomy->name),
			"std"     => ""
		);
		
	endforeach;
	// end each extra taxonomy
	
	
	return $options;	
}



/**
 * Contextual Help
 *
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0
 *
 */
function qts_options_page_contextual_help() {
	
	
	$text 	= "<h3>" . __('Qtranslate Settings - Contextual Help','qts') . "</h3>";
	$text 	.= "<p>" . __('Contextual help goes here. You may want to use different html elements to format your text as you want.','qts') . "</p>";
	
	return $text;
}
<?php

// page settings sections & fields as well as the contextual help text.
include_once('qtranslate-slug-settings-options.php');


/**
 * Prints upgrade form in Qtranslate Slug admin page
 *
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0
 *
 * @return array
 */
function qts_upgrade() {
	global $qtranslate_slug;
	
	if ( !$qtranslate_slug->check_old_data() ) return;
	
	echo "<div id=\"qts-upgrade-box\" class=\"updated\" style=\"margin: 15px 0; margin-bottom:25px; padding: 10px\">" . PHP_EOL;
	
	echo "<h3>" . __('Upgrade your data', 'qts') . "</h3>" . PHP_EOL;
	echo "<p>" . __('There are slugs stored with old data system. Please upgrade your data pressing upgrade button:', 'qts') . "</p>" . PHP_EOL;
	
	echo "<div id=\"qts-upgrade-form\">" . PHP_EOL;
	echo "<input type=\"hidden\" id=\"qts-upgrade-action\" name=\"qts-upgrade-action\" value=\"qts-upgrade-check\" />" .PHP_EOL;
	echo "<input type=\"hidden\" id=\"qts-upgrade-nonce\" name=\"qts-upgrade-nonce\" value=\"". wp_create_nonce('qts-upgrade') . "\" />" .PHP_EOL;
	echo "<p><a id=\"qts-upgrade-button\" href=\"#\" class=\"button-primary\">" . __('upgrade now', 'qts') . "</a><img src=\"".admin_url('images/wpspin_light.gif')."\" class=\"qts-loading\" id=\"qts-loading\" alt=\"\"></p>" . PHP_EOL;
	echo "</div></div>" . PHP_EOL;
}


/**
 * AJAX: upgrade old database to new system
 *
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0
 *
 * @return boolean
 */
function qts_process_old_data( $old_data = null, $type = 'post' ) {
	global $wpdb, $qtranslate_slug;
	
	if ( is_null($old_data) || empty($old_data) ) return 0;
	foreach ($old_data as $row) {
		switch ($row->qts_type) {
			case 1:
			case 2:
				update_post_meta( $row->qts_id, $qtranslate_slug->get_meta_key($row->qts_lang), $row->qts_slug);
				break;
			case 3:
			case 4:
				update_term_meta( $row->qts_id, $qtranslate_slug->get_meta_key($row->qts_lang), $row->qts_slug);
				break;
			case 5:
				if ($type == 'post')
					update_post_meta( $row->qts_id, $qtranslate_slug->get_meta_key($row->qts_lang), $row->qts_slug);
				
				if ($type == 'term')
					update_term_meta( $row->qts_id, $qtranslate_slug->get_meta_key($row->qts_lang), $row->qts_slug);
				break;
		};
	}
	$wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}qtranslate_slug");
	
	return 1;
}

function qts_upgrade_response($type = 0, $slug = null) {
	switch ( $type ) {
		default:
		case 0:
			$response = array(
				'status' => 0,
				'message' => __('Sorry, some error happened. Refresh this page and try again please.', 'qts'),
			);
			break;
		   
		case 1:
			$response = array(
				'status' => 1,
				'message' => __('Congratulations, your data has been upgraded, you are up to date.', 'qts'),
			);
			break;
		case 2:
			$response = array(
				'status' => 2,
				'message' => sprintf(__('One step more, select what type of slug is this: <strong>%s</strong>', 'qts'), $slug),
				'options' => array( 'post' => __('Post, Page or Custom post type', 'qts'), 'term' => __('Category, tag or custom taxonomy', 'qts') )
			);
			break;
	}
	
	return $response;
}



/**
 * AJAX: upgrade old database to new system
 *
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0
 *
 * @return JSON object
 */
function qts_upgrade_check() {
	global $qtranslate_slug;
	
	$old_data = $qtranslate_slug->check_old_data();
	
	if ( wp_verify_nonce( $_POST['nonce'], 'qts-upgrade') ):
	
		// if data process to save...
		if ($old_data) {
			
			// if defined data type 5, process to upgrade
			if ( isset($_POST['type']) ):
				
				$res =  qts_process_old_data($old_data, $_POST['type']);
				
				$response = qts_upgrade_response($res);
				
			else :
				
				// define wich type of data is 5
				$array_of_5 = array();
				foreach ( $old_data as $row )
					if ( $row->qts_type == 5 ) $array_of_5[] = $row->qts_slug;
				
				if (!empty($array_of_5)) $response = qts_upgrade_response(2, implode(', ', $array_of_5));
				
				// if no data type 5, process to upgrade
				if (!isset($response)) {
					$res =  qts_process_old_data($old_data);
					$response = qts_upgrade_response($res);
				}
				
			endif;
			
		
		// if not continue	
		} else {
	
			$response = qts_upgrade_response();
		
		}
	
	else:
		
		$response = qts_upgrade_response();
		
	endif;
	
	// response output
	header( "Content-Type: application/json" );
	echo json_encode($response);
	exit;
}
add_action('wp_ajax_qts-upgrade-check',  'qts_upgrade_check');



/**
 * Helper function for defining variables for the current page
 *
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0
 *
 * @return array
 */
function qts_get_settings() {
	
	$output = array();
	
	// put together the output array 
	$output['qts_option_name']		= QTS_OPTIONS_NAME; // the option name as used in the get_option() call.
	$output['qts_page_title'] 		= __('Qtranslate Slug options', 'qts'); // the settings page title
	$output['qts_page_sections'] 	= qts_options_page_sections(); // the settings sections
	$output['qts_page_fields'] 		= qts_options_page_fields(); // the settings fields
	$output['qts_page_styles'] 		= qts_options_page_styles(); // the settings for style
	
	
	$output['qts_contextual_help'] = qts_options_page_contextual_help(); // the contextual help
	
return $output;
}



/**
 * Helper function for registering our form field settings
 *
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0
 *
 * src: http://alisothegeek.com/2011/01/wordpress-settings-api-tutorial-1/
 * @param (array) $args The array of arguments to be used in creating the field
 * @return function call
 */
function qts_create_settings_field( $args = array() ) {
	// default array to overwrite when calling the function
	$defaults = array(
		'id'      => 'default_field', // the ID of the setting in our options array, and the ID of the HTML form element
		'title'   => 'Default Field', // the label for the HTML form element
		'desc'    => 'This is a default description.', 	// the description displayed under the HTML form element
		'std'     => '', 							// the default value for this setting
		'type'    => 'text', 					// the HTML form element to use
		'section' => 'main_section',	// the section this setting belongs to must match the array key of a section in qts_options_page_sections()
		'choices' => array(), 			// (optional): the values in radio buttons or a drop-down menu
		'class'   => '' 						// the HTML form element class. Is used for validation purposes and may be also use for styling if needed.
	);
	
	// "extract" to be able to use the array keys as variables in our function output below
	extract( wp_parse_args( $args, $defaults ) );
	
	// additional arguments for use in form field output in the function qts_show_form_field!
	$field_args = array(
		'type'      => $type,
		'id'        => $id,
		'desc'      => $desc,
		'std'       => $std,
		'choices'   => $choices,
		'label_for' => $id,
		'class'     => $class
	);
  
  

	add_settings_field( $id, $title, 'qts_show_form_field', __FILE__, $section, $field_args );

}



/**
 * Register our setting, settings sections and settings fields
 *
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0
 *
 */
function qts_register_settings(){
	
	// get the settings sections array
	$settings_output = qts_get_settings();
	$qts_option_name = $settings_output['qts_option_name'];
	
	//setting
	register_setting($qts_option_name, $qts_option_name, 'qts_validate_options' );
	
	//sections
	if(!empty($settings_output['qts_page_sections'])){
		// call the "add_settings_section" for each!
		foreach ( $settings_output['qts_page_sections'] as $id => $title ) {
			add_settings_section( $id, $title, 'qts_section_fn', __FILE__);
		}
	}
		
	//fields
	if(!empty($settings_output['qts_page_fields'])){
		// call the "add_settings_field" for each!
		foreach ($settings_output['qts_page_fields'] as $option) {
			qts_create_settings_field($option);
		}
	}
	//style
	if(!empty($settings_output['qts_page_styles'])){
		// call the "add_settings_field" for each
		foreach ($settings_output['qts_page_styles'] as $styleoption) {
			qts_create_settings_field($styleoption);
		}
	}
}
add_action( 'admin_init', 'qts_register_settings' );



/**
 * Group scripts (js & css)
 *
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0
 *
 */
function qts_settings_scripts() {
	global $qtranslate_slug;
	
	wp_enqueue_style('qts_theme_settings_css', plugins_url( 'assets/css/qts-settings.css' , dirname(__FILE__)  ) );
	wp_enqueue_script( 'qts_theme_settings_js', plugins_url( 'assets/js/qts-settings.js' , dirname(__FILE__)  ), array('jquery'));
	
	if ($qtranslate_slug->check_old_data()) {
		wp_enqueue_script('qts_theme_settings_upgrade_js', plugins_url( 'assets/js/qts-settings-upgrade.js' , dirname(__FILE__) ), array('jquery') );
	}
}



/**
 * The Admin menu page
 *
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0
 *
 */
function qts_add_menu() {
	global $current_screen;

	$settings_output = qts_get_settings();
	// collect our contextual help text
	$qts_contextual_help = $settings_output['qts_contextual_help'];
	
	// Display Settings Page link under the "Appearance" Admin Menu
	$qts_settings_page = add_options_page(__('Qtranslate Slug options', 'qts'), __('Slug options', 'qts'), 'manage_options', QTS_PAGE_BASENAME, 'qts_show_settings_page');
		// contextual help
		/*
		if ($qts_settings_page) {
			$current_screen = get_current_screen();
			//$current_screen->add_help_tab( array( $qts_settings_page, $qts_contextual_help ));
		}
		*/
		// css & js
		add_action( 'load-'. $qts_settings_page, 'qts_settings_scripts' );	
}
add_action( 'admin_menu', 'qts_add_menu' );



////////////////////////////////////////////////////////////////////////////////////////
	
// Callback functions



/**
 * Section HTML, displayed before the first option
 *
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0
 *
 * @return echoes output
 */
function qts_section_fn($page_section = false) {
	
	if ( !$page_section || !isset($page_section['id']) ) return;
	
	switch ($page_section['id']) {
		case 'post_types':	
		
			echo "<p>" . __('For example, the post_type <kbd>books</kbd>, in Spanish would be displayed as <code>http://example.org/es/libros/post-type-name/</code>. If you leave this blank will use the default option when you <a href="http://codex.wordpress.org/Function_Reference/register_post_type">registered</a> the post_type.', 'qts') . "</p>";
			break;
		
		case 'taxonomies':
			
			echo "<p>" . __('For example, the taxonomy <kbd>category</kbd>, in Spanish would be displayed as <code>http://example.org/es/categoria/taxonomy-name/</code>. If you leave this blank will use the default option when you <a href="http://codex.wordpress.org/Function_Reference/register_taxonomy">registered</a> the taxonomy (if you previously setup a base permastruct for <u>categories</u> or <u>tags</u> in <a href="options-permalink.php">permalinks</a> page, these bases will be overwritten by the translated ones).', 'qts') . "</p>";
			break;
  		case 'styles':

    		echo "<p>" . __('The default styles are very minimal, and you can include them or not.', 'qts') . "</p>\n";    
    		break;
	}
}



/**
 * Form Fields HTML: all form field types share the same function
 *
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0
 *
 * @return echoes output
 */
function qts_show_form_field($args = array()) {
	global $qtranslate_slug;
	
	extract( $args );
	
	// get the settings sections array
	$settings_output = qts_get_settings();
	$options = $qtranslate_slug->get_options();
	
	// pass the standard value if the option is not yet set in the database
	if ( !isset( $options[$id] ) && 'type' != 'checkbox' ) {
		$options[$id] = $std;
	}
	
	// additional field class. output only if the class is defined in the create_setting arguments
	$field_class = ($class != '') ? ' ' . $class : '';
	
	// switch html display based on the setting type.	
	switch ( $type ) {
		case 'text':
			$options[$id] = stripslashes($options[$id]);
			$options[$id] = esc_attr( $options[$id]);
			echo "<input class='regular-text$field_class' type='text' id='$id' name='" . QTS_OPTIONS_NAME . "[$id]' value='$options[$id]' />";
			echo ($desc != '') ? "<br /><span class='description'>$desc</span>" : "";
		break;
		
		case "multi-text":
			foreach($choices as $item) {
				
				$item = explode("|",$item); // cat_name|cat_slug
				$item[0] = esc_html__($item[0], 'qts');
				
				if (!empty($options[$id])) {
					foreach ($options[$id] as $option_key => $option_val){
						if ($item[1] == $option_key) {
							$value = $option_val;
						}
					}
				} else {
					$value = '';
				}
				
				echo "<span>$item[0]:</span> <input class='$field_class' type='text' id='$id|$item[1]' name='" . QTS_OPTIONS_NAME . "[$id|$item[1]]' value='$value' /><br/>";
			}
			echo ($desc != '') ? "<span class='description'>$desc</span>" : "";
		break;
		
		case 'textarea':
			$options[$id] = stripslashes($options[$id]);
			$options[$id] = esc_html( $options[$id]);
			echo "<textarea class='textarea$field_class' type='text' id='$id' name='" . QTS_OPTIONS_NAME . "[$id]' rows='5' cols='30'>$options[$id]</textarea>";
			echo ($desc != '') ? "<br /><span class='description'>$desc</span>" : ""; 		
		break;
		
		case 'select':
			echo "<select id='$id' class='select$field_class' name='" . QTS_OPTIONS_NAME . "[$id]'>";
				foreach($choices as $item) {
					$value 	= esc_attr($item, 'qts');
					$item 	= esc_html($item, 'qts');
					
					$selected = ($options[$id]==$value) ? 'selected="selected"' : '';
					echo "<option value='$value' $selected>$item</option>";
				}
			echo "</select>";
			echo ($desc != '') ? "<br /><span class='description'>$desc</span>" : ""; 
		break;
		
		case 'select2':
			echo "<select id='$id' class='select$field_class' name='" . QTS_OPTIONS_NAME . "[$id]'>";
			foreach($choices as $item) {
				
				$item = explode("|",$item);
				$item[0] = esc_html($item[0], 'qts');
				
				$selected = ($options[$id]==$item[1]) ? 'selected="selected"' : '';
				echo "<option value='$item[1]' $selected>$item[0]</option>";
			}
			echo "</select>";
			echo ($desc != '') ? "<br /><span class='description'>$desc</span>" : "";
		break;
		
		case 'checkbox':
			echo "<input class='checkbox$field_class' type='checkbox' id='$id' name='" . QTS_OPTIONS_NAME . "[$id]' value='1' " . checked( $options[$id], 1, false ) . " />";
			echo ($desc != '') ? "<br /><span class='description'>$desc</span>" : "";
		break;
		
		case "multi-checkbox":
			foreach($choices as $item) {
				
				$item = explode("|",$item);
				$item[0] = esc_html($item[0], 'qts');
				
				$checked = '';
				
			    if ( isset($options[$id][$item[1]]) ) {
					if ( $options[$id][$item[1]] == 'true') {
			   			$checked = 'checked="checked"';
					}
				}
				
				echo "<input class='checkbox$field_class' type='checkbox' id='$id|$item[1]' name='" . QTS_OPTIONS_NAME . "[$id|$item[1]]' value='1' $checked /> $item[0] <br/>";
			}
			echo ($desc != '') ? "<br /><span class='description'>$desc</span>" : "";
		break;

		case "multi-radio":
			foreach($choices as $index => $item) {
				
				$item = explode("|",$item);
				$item_key = (count($item) > 1) ? esc_html($item[0], 'qts') : esc_html(end($item), 'qts');
				$item_value = (count($item) > 1) ? esc_html($item[1], 'qts') : esc_html(end($item), 'qts');
				
				$checked = '';
				
			    if ( isset($options[$id]) && $options[$id] === $item_value) {
			   		$checked = 'checked="checked"';
				}
				
				echo "<label for='$id|$item_value'><input class='radio$field_class' type='radio' id='$id|$item_value' name='" . QTS_OPTIONS_NAME . "[$id]' value='$item_value' $checked /> <strong>$item_key</strong>";
				if (isset($desc[$index]) && !empty($desc[$index])) {
					echo ": " . $desc[$index];
				}
				echo "</label>";
			}
			echo (!is_array($desc) && $desc != '') ? "<br /><span class='description'>$desc</span>" : "";
		break;
	}
}



/**
 * Validates base slugs per 'type' (post_type | taxonomy) and 'language' 
 * 
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0
 *
 */
function qts_sanitize_bases($base_slugs = false) {
	
	if ( !$base_slugs || empty($base_slugs) ) return;
	
	$base_slugs_processed = array();
	$base_founded = array();
	
	// changing array structure
	foreach ($base_slugs as $type => $base) {
		foreach ($base as $lang => $value) {
			if ($value != ""):
				$base_value = $value;
				$count = 2;
				while (in_array($value, $base_founded)) {
					$value = "$base_value-$count";
					$count++;
				}
				$base_founded[] = $base_slugs[$type][$lang] = $value;
			endif;
		}
	}
	
	return $base_slugs;
}



/**
 * Admin Settings Page HTML
 * 
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0
 *
 * @return echoes output
 */
function qts_show_settings_page() {
	// get the settings sections array
	$settings_output = qts_get_settings();
?>
	<div class="wrap">
		<div class="icon32" id="icon-options-general"></div>
		<h2><?php echo $settings_output['qts_page_title']; ?></h2>
		
		<p><?php  _e('If you activated previously the <a href="options-permalink.php">pretty permalinks</a>, in this section you can translate the <abbr title="en inglés, Universal Resource Locator">URLs</abbr> <strong>bases</strong> for <a href="http://codex.wordpress.org/Function_Reference/register_post_type#Arguments">public</a> post_types, categories, tags and taxonomies.', 'qts'); ?> </p>
		
		<form action="options.php" method="post">
			<?php 
			// upgrade notify
			qts_upgrade();
			// http://codex.wordpress.org/Function_Reference/settings_fields
			settings_fields($settings_output['qts_option_name']);
      
			// http://codex.wordpress.org/Function_Reference/do_settings_sections
			do_settings_sections(__FILE__);
			// rewrite rules
			flush_rewrite_rules();
			?>
	  <?php $css_path = plugin_dir_url(dirname(__FILE__)).'/assets/css/qts-default.css';
            $file_styles = file_get_contents($css_path);
            
             
            ?>
            <p><?php  _e('If you selected "none", copy and use these styles as you see fit:','qts'); ?> </p>
            <textarea name="textarea" rows="10" cols="80"><?php echo $file_styles; ?></textarea>;
			<p class="submit">
				<input name="Submit" type="submit" class="button-primary" value="<?php esc_attr_e('Save Changes','qts'); ?>" />
			</p>
			
		</form>
	</div><!-- wrap -->
<?php }



/**
 * Validate input
 *
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0 
 * 
 * @return array
 */
function qts_validate_options($input) {
	
	// for enhanced security, create a new empty array
	$valid_input = array();
	
	// collect only the values we expect and fill the new $valid_input array
	// i.e. whitelist our option IDs
	
	// get the settings sections array
	$settings_output = qts_get_settings();
		
    $styleoptions =  $settings_output['qts_page_styles'];
    
	$slugoptions = $settings_output['qts_page_fields'];
		
    $options = array_merge($styleoptions,$slugoptions);

	// run a foreach and switch on option type
	foreach ($options as $option):
	
		switch ( $option['type'] ):
			case 'text':
				//switch validation based on the class!
				switch ( $option['class'] ) {
					//for numeric 
					case 'numeric':
						//accept the input only when numeric!
						$input[$option['id']] 		= trim($input[$option['id']]); // trim whitespace
						$valid_input[$option['id']] = (is_numeric($input[$option['id']])) ? $input[$option['id']] : 'Expecting a Numeric value!';
						
						// register error
						if(is_numeric($input[$option['id']]) == FALSE) {
							add_settings_error(
								$option['id'], // setting title
								QTS_PREFIX . '_txt_numeric_error', // error ID
								__('Expecting a Numeric value! Please fix.', 'qts'), // error message
								'error' // type of message
							);
						}
					break;
					
					//for multi-numeric values (separated by a comma)
					case 'multinumeric':
						//accept the input only when the numeric values are comma separated
						$input[$option['id']] 		= trim($input[$option['id']]); // trim whitespace
						
						if($input[$option['id']] !=''){
							// /^-?\d+(?:,\s?-?\d+)*$/ matches: -1 | 1 | -12,-23 | 12,23 | -123, -234 | 123, 234  | etc.
							$valid_input[$option['id']] = (preg_match('/^-?\d+(?:,\s?-?\d+)*$/', $input[$option['id']]) == 1) ? $input[$option['id']] : __('Expecting comma separated numeric values','qts');
						}else{
							$valid_input[$option['id']] = $input[$option['id']];
						}
						
						// register error
						if($input[$option['id']] !='' && preg_match('/^-?\d+(?:,\s?-?\d+)*$/', $input[$option['id']]) != 1) {
							add_settings_error(
								$option['id'], // setting title
								QTS_PREFIX . '_txt_multinumeric_error', // error ID
								__('Expecting comma separated numeric values! Please fix.','qts'), // error message
								'error' // type of message
							);
						}
					break;
					
					//for no html
					case 'nohtml':
						//accept the input only after stripping out all html, extra white space etc!
						$input[$option['id']] 		= sanitize_text_field($input[$option['id']]); // need to add slashes still before sending to the database
						$valid_input[$option['id']] = addslashes($input[$option['id']]);
					break;
					
					//for url
					case 'url':
						//accept the input only when the url has been sanited for database usage with esc_url_raw()
						$input[$option['id']] 		= trim($input[$option['id']]); // trim whitespace
						$valid_input[$option['id']] = esc_url_raw($input[$option['id']]);
					break;
					
					//for email
					case 'email':
						//accept the input only after the email has been validated
						$input[$option['id']] 		= trim($input[$option['id']]); // trim whitespace
						if($input[$option['id']] != ''){
							$valid_input[$option['id']] = (is_email($input[$option['id']])!== FALSE) ? $input[$option['id']] : __('Invalid email', 'qts');
						}elseif($input[$option['id']] == ''){
							$valid_input[$option['id']] = __('This setting field cannot be empty! Please enter a valid email address.', 'qts');
						}
						
						// register error
						if(is_email($input[$option['id']])== FALSE || $input[$option['id']] == '') {
							add_settings_error(
								$option['id'], // setting title
								QTS_PREFIX . '_txt_email_error', // error ID
								__('Please enter a valid email address.', 'qts'), // error message
								'error' // type of message
							);
						}
					break;
					
					// a "cover-all" fall-back when the class argument is not set
					default:
						// accept only a few inline html elements
						$allowed_html = array(
							'a' => array('href' => array (),'title' => array ()),
							'b' => array(),
							'em' => array (), 
							'i' => array (),
							'strong' => array()
						);
						// trim whitespace
						$input[$option['id']] 		= trim($input[$option['id']]);
						// find incorrectly nested or missing closing tags and fix markup
						$input[$option['id']] 		= force_balance_tags($input[$option['id']]);
						// need to add slashes still before sending to the database
						$input[$option['id']] 		= wp_kses( $input[$option['id']], $allowed_html);
          
						$valid_input[$option['id']] = addslashes($input[$option['id']]); 
					break;
				}
			break;
			
			case "multi-text":
				// this will hold the text values as an array of 'key' => 'value'
				unset($textarray);
				
				$text_values = array();
				foreach ($option['choices'] as $k => $v ) {
					// explode the connective
					$pieces = explode("|", $v);
					
					$text_values[] = $pieces[1];
				}
				
				foreach ($text_values as $v ) {		
					
					// Check that the option isn't empty
					if (!empty($input[$option['id'] . '|' . $v])) {
						// If it's not null, make sure it's sanitized, add it to an array
						switch ($option['class']) {
							// different sanitation actions based on the class create you own cases as you need them
							
							//for numeric input
							case 'numeric':
								//accept the input only if is numberic!
								$input[$option['id'] . '|' . $v]= trim($input[$option['id'] . '|' . $v]); // trim whitespace
								$input[$option['id'] . '|' . $v]= (is_numeric($input[$option['id'] . '|' . $v])) ? $input[$option['id'] . '|' . $v] : '';
							break;
							
							case 'qts-slug':
								// strip all html tags and white-space.
								$exploded_types = explode('_', $option['id']);
								$type_ = end($exploded_types  );
								$input[$option['id'] . '|' . $v]= sanitize_title( sanitize_text_field( $input[$option['id'] . '|' . $v] ) );
								$input[$option['id'] . '|' . $v]= addslashes($input[$option['id'] . '|' . $v]);
							break;
							
							// a "cover-all" fall-back when the class argument is not set
							default:
								// strip all html tags and white-space.
								$input[$option['id'] . '|' . $v]= sanitize_text_field($input[$option['id'] . '|' . $v]); // need to add slashes still before sending to the database
								$input[$option['id'] . '|' . $v]= addslashes($input[$option['id'] . '|' . $v]);
							break;
						}
						// pass the sanitized user input to our $textarray array
						$textarray[$v] = $input[$option['id'] . '|' . $v];
					
					} else {
						$textarray[$v] = '';
					}
				}
				// pass the non-empty $textarray to our $valid_input array
				if (!empty($textarray)) {
					$valid_input[$option['id']] = $textarray;
				}
			break;
			
			case 'textarea':
				//switch validation based on the class!
				switch ( $option['class'] ) {
					//for only inline html
					case 'inlinehtml':
						// accept only inline html
						// trim whitespace
						$input[$option['id']] 		= trim($input[$option['id']]);
         				// find incorrectly nested or missing closing tags and fix markup
						$input[$option['id']] 		= force_balance_tags($input[$option['id']]);
						//wp_filter_kses expects content to be escaped!
						$input[$option['id']] 		= addslashes($input[$option['id']]);
          				//calls stripslashes then addslashes
						$valid_input[$option['id']] = wp_filter_kses($input[$option['id']]);
					break;
					
					//for no html
					case 'nohtml':
						//accept the input only after stripping out all html, extra white space etc!
						// need to add slashes still before sending to the database
						$input[$option['id']] 		= sanitize_text_field($input[$option['id']]); 
						$valid_input[$option['id']] = addslashes($input[$option['id']]);
					break;
					
					//for allowlinebreaks
					case 'allowlinebreaks':
						//accept the input only after stripping out all html, extra white space etc!
						// need to add slashes still before sending to the database
						$input[$option['id']] 		= wp_strip_all_tags($input[$option['id']]); 
						$valid_input[$option['id']] = addslashes($input[$option['id']]);
					break;
					
					// a "cover-all" fall-back when the class argument is not set
					default:
						// accept only limited html
						//my allowed html
						$allowed_html = array(
							'a' 			=> array('href' => array (),'title' => array ()),
							'b' 			=> array(),
							'blockquote' 	=> array('cite' => array ()),
							'br' 			=> array(),
							'dd' 			=> array(),
							'dl' 			=> array(),
							'dt' 			=> array(),
							'em' 			=> array (), 
							'i' 			=> array (),
							'li' 			=> array(),
							'ol' 			=> array(),
							'p' 			=> array(),
							'q' 			=> array('cite' => array ()),
							'strong' 	=> array(),
							'ul' 			=> array(),
							'h1' 			=> array('align' => array (),'class' => array (),'id' => array (), 'style' => array ()),
							'h2' 			=> array('align' => array (),'class' => array (),'id' => array (), 'style' => array ()),
							'h3' 			=> array('align' => array (),'class' => array (),'id' => array (), 'style' => array ()),
							'h4' 			=> array('align' => array (),'class' => array (),'id' => array (), 'style' => array ()),
							'h5' 			=> array('align' => array (),'class' => array (),'id' => array (), 'style' => array ()),
							'h6' 			=> array('align' => array (),'class' => array (),'id' => array (), 'style' => array ())
						);
						
						$input[$option['id']] 		= trim($input[$option['id']]); // trim whitespace
						$input[$option['id']] 		= force_balance_tags($input[$option['id']]); // find incorrectly nested or missing closing tags and fix markup
						$input[$option['id']] 		= wp_kses( $input[$option['id']], $allowed_html); // need to add slashes still before sending to the database
						$valid_input[$option['id']] = addslashes($input[$option['id']]);							
					break;
				}
			break;
			
			case 'select':
				// check to see if the selected value is in our approved array of values!
				$valid_input[$option['id']] = (in_array( $input[$option['id']], $option['choices']) ? $input[$option['id']] : '' );
			break;
			
			case 'select2':
				// process $select_values
					$select_values = array();
					foreach ($option['choices'] as $k => $v) {
						// explode the connective
						$pieces = explode("|", $v);
						
						$select_values[] = $pieces[1];
					}
				// check to see if selected value is in our approved array of values!
				$valid_input[$option['id']] = (in_array( $input[$option['id']], $select_values) ? $input[$option['id']] : '' );
			break;
			
			case 'checkbox':
				// if it's not set, default to null!
				if (!isset($input[$option['id']])) {
					$input[$option['id']] = null;
				}
				// Our checkbox value is either 0 or 1
				$valid_input[$option['id']] = ( $input[$option['id']] == 1 ? 1 : 0 );
			break;
			
			case 'multi-checkbox':
				unset($checkboxarray);
				$check_values = array();
				foreach ($option['choices'] as $k => $v ) {
					// explode the connective
					$pieces = explode("|", $v);
					
					$check_values[] = $pieces[1];
				}
				
				foreach ($check_values as $v ) {		
					
					// Check that the option isn't null
					if (!empty($input[$option['id'] . '|' . $v])) {
						// If it's not null, make sure it's true, add it to an array
						$checkboxarray[$v] = 'true';
					}
					else {
						$checkboxarray[$v] = 'false';
					}
				}
				// Take all the items that were checked, and set them as the main option
				if (!empty($checkboxarray)) {
					$valid_input[$option['id']] = $checkboxarray;
				}
			break;

			case 'multi-radio':
				$valid_input[$option['id']] = (empty($input) || !isset($input[$option['id']])) ? $option['std'] : $input[$option['id']];
			break;
			
		endswitch;
  
      	if (!empty($valid_input) && $valid_input[$option['id']] === "qts-slug" ) {
        	$valid_input = qts_sanitize_bases($valid_input);
      	} else {
		    $valid_input= $valid_input;
      	}
  
	endforeach;    
    
	return $valid_input;
}



/**
 * Helper function for creating admin messages
 *
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0 
 *
 * src: http://www.wprecipes.com/how-to-show-an-urgent-message-in-the-wordpress-admin-area
 *
 * @param (string) $message The message to echo
 * @param (string) $msgclass The message class
 * @return echoes the message
 */
function qts_show_msg($message, $msgclass = 'info') {
	echo "<div id='message' class='$msgclass'>$message</div>";
}



/**
 * Callback function for displaying admin messages
 *
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0 
 *
 * @return calls qts_show_msg()
 */
function qts_admin_msgs() {
	global $current_screen;
	
	// check for our settings page - need this in conditional further down
	$qts_settings_pg = isset($_GET['page']) ? strpos($_GET['page'], QTS_PAGE_BASENAME) : '';
	// collect setting errors/notices: 
	// http://codex.wordpress.org/Function_Reference/get_settings_errors
	$set_errors = get_settings_errors(); 
	
	// display admin message only for the admin to see, only on our settings page
	// and only when setting errors/notices are returned!	
	if(current_user_can ('manage_options') && $qts_settings_pg !== false && !empty($set_errors)){

		// have our settings succesfully been updated? 
		if($set_errors[0]['code'] == 'settings_updated' && isset($_GET['settings-updated'])){
			qts_show_msg("<p>" . $set_errors[0]['message'] . "</p>", 'updated');
		
		// have errors been found?
		}else{
			// there maybe more than one so run a foreach loop.
			foreach($set_errors as $set_error){
				// set the title attribute to match the error "setting title" - need this in js file
				qts_show_msg("<p class='setting-error-message' title='" . $set_error['setting'] . "'>" . $set_error['message'] . "</p>", 'error');
			}
		}
	}
}
add_action('admin_notices', 'qts_admin_msgs');
<?php
/**
 * Install Term meta table - setup table, store db version for future updates
 */
if ( !function_exists('install_term_meta_table') ):
function install_term_meta_table() {
	global $wpdb;

	$collate = '';
	//if($wpdb->supports_collation())//deprecated, was a reason for activation admin notice
	if($wpdb->has_cap( 'collation' )) {
		if(!empty($wpdb->charset)) $collate = "DEFAULT CHARACTER SET $wpdb->charset";
		if(!empty($wpdb->collate)) $collate .= " COLLATE $wpdb->collate";
	}

	$sql = "CREATE TABLE IF NOT EXISTS ". $wpdb->prefix . "termmeta" ." (
		`meta_id` 				bigint(20) NOT NULL AUTO_INCREMENT,
	  	`term_id` 				bigint(20) NOT NULL DEFAULT '0',
	  	`meta_key` 				varchar(255) NULL,
	  	`meta_value` 			longtext NULL,
	  	PRIMARY KEY id (`meta_id`)) $collate;";
	$wpdb->query($sql);
}
endif;



function simple_post_meta_define_table() {
	global $wpdb;
	$wpdb->termmeta = $wpdb->prefix . 'termmeta';
}
add_action( 'init', 'simple_post_meta_define_table' );



/**
 * Updates metadata cache for list of term IDs.
 *
 * Performs SQL query to retrieve the metadata for the term IDs and updates the
 * metadata cache for the terms. Therefore, the functions, which call this
 * function, do not need to perform SQL queries on their own.
 *
 * @param array $term_ids List of post IDs.
 * @return bool|array Returns false if there is nothing to update or an array of metadata.
 */
if ( !function_exists('update_termmeta_cache') ):
	function update_termmeta_cache($term_ids) {
		return update_meta_cache('term', $term_ids);
	}
endif;



/**
 * Add meta data field to a term.
 *
 * @param int $term_id Term ID.
 * @param string $key Metadata name.
 * @param mixed $value Metadata value.
 * @param bool $unique Optional, default is false. Whether the same key should not be added.
 * @return bool False for failure. True for success.
 */
if ( !function_exists('add_term_meta') ):
	function add_term_meta( $term_id, $meta_key, $meta_value, $unique = false ) {
		return add_metadata('term', $term_id, $meta_key, $meta_value, $unique);
	}
endif;



/**
 * Remove metadata matching criteria from a term.
 *
 * You can match based on the key, or key and value. Removing based on key and
 * value, will keep from removing duplicate metadata with the same key. It also
 * allows removing all metadata matching key, if needed.
 *
 * @param int $term_id Term ID
 * @param string $meta_key Metadata name.
 * @param mixed $meta_value Optional. Metadata value.
 * @return bool False for failure. True for success.
 */
if ( !function_exists('delete_term_meta') ):
	function delete_term_meta( $term_id, $meta_key, $meta_value = '' ) {
		return delete_metadata('term', $term_id, $meta_key, $meta_value);
	}
endif;



/**
 * Retrieve term meta field for a term.
 *
 * @param int $term_id Term ID.
 * @param string $key The meta key to retrieve.
 * @param bool $single Whether to return a single value.
 * @return mixed Will be an array if $single is false. Will be value of meta data field if $single
 *  is true.
 */
if ( !function_exists('get_term_meta') ):
	function get_term_meta( $term_id, $key, $single = false ) {
		return get_metadata('term', $term_id, $key, $single);
	}
endif;



/**
 * Update term meta field based on term ID.
 *
 * Use the $prev_value parameter to differentiate between meta fields with the
 * same key and term ID.
 *
 * If the meta field for the term does not exist, it will be added.
 *
 * @param int $term_id Term ID.
 * @param string $key Metadata key.
 * @param mixed $value Metadata value.
 * @param mixed $prev_value Optional. Previous value to check before removing.
 * @return bool False on failure, true if success.
 */
if ( !function_exists('update_term_meta') ):
	function update_term_meta( $term_id, $meta_key, $meta_value, $prev_value = '' ) {
		return update_metadata('term', $term_id, $meta_key, $meta_value, $prev_value);
	}
endif;



/**
 * Delete everything from term meta matching meta key.
 *
 * @param string $term_meta_key Key to search for when deleting.
 * @return bool Whether the term meta key was deleted from the database
 */
if ( !function_exists('delete_term_meta_by_key') ):
	function delete_term_meta_by_key($term_meta_key) {
		if ( !$term_meta_key )
			return false;

		global $wpdb;
		$term_ids = $wpdb->get_col($wpdb->prepare("SELECT DISTINCT term_id FROM $wpdb->termmeta WHERE meta_key = %s", $term_meta_key));
		if ( $term_ids ) {
			$termmetaids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->termmeta WHERE meta_key = %s", $term_meta_key ) );
			$in = implode( ',', array_fill(1, count($termmetaids), '%d'));
			do_action( 'delete_termmeta', $termmetaids );
			$wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->termmeta WHERE meta_id IN($in)", $termmetaids ));
			do_action( 'deleted_termmeta', $termmetaids );
			foreach ( $term_ids as $term_id )
				wp_cache_delete($term_id, 'term_meta');
			return true;
		}
		return false;
	}
endif;



/**
 * Retrieve term meta fields, based on term ID.
 *
 * The term meta fields are retrieved from the cache, so the function is
 * optimized to be called more than once. It also applies to the functions, that
 * use this function.
 *
 * @param int $term_id term ID
 * @return array
 */
if ( !function_exists('add_term_meta') ):
	function get_term_custom( $term_id ) {
		$term_id = (int) $term_id;

		if ( ! wp_cache_get($term_id, 'term_meta') )
			update_termmeta_cache($term_id);

		return wp_cache_get($term_id, 'term_meta');
	}
endif;



/**
 * Retrieve meta field names for a term.
 *
 * If there are no meta fields, then nothing (null) will be returned.
 *
 * @param int $term_id term ID
 * @return array|null Either array of the keys, or null if keys could not be retrieved.
 */
if ( !function_exists('get_term_custom_keys') ):
	function get_term_custom_keys( $term_id ) {
		$custom = get_term_custom( $term_id );

		if ( !is_array($custom) )
			return;

		if ( $keys = array_keys($custom) )
			return $keys;
	}
endif;



/**
 * Retrieve values for a custom term field.
 *
 * The parameters must not be considered optional. All of the term meta fields
 * will be retrieved and only the meta field key values returned.
 *
 * @param string $key Meta field key.
 * @param int $term_id Term ID
 * @return array Meta field values.
 */
if ( !function_exists('get_term_custom_values') ):
	function get_term_custom_values( $key = '', $term_id ) {
		if ( !$key )
			return null;

		$custom = get_term_custom($term_id);

		return isset($custom[$key]) ? $custom[$key] : null;
	}
endif;
# Copyright (C) 2012 qTranslate slug
# This file is distributed under the same license as the qTranslate slug package.
msgid ""
msgstr ""
"Project-Id-Version: qTranslate slug 1.0\n"
"Report-Msgid-Bugs-To: http://wordpress.org/tag/qtranslate-slug\n"
"POT-Creation-Date: 2012-05-27 20:27:55+00:00\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"PO-Revision-Date: 2012-06-17 03:37+0100\n"
"Last-Translator: Carlos Sanz <carlos.sanz@gmail.com>\n"
"Language-Team: Carlos Sanz Garcia <carlos.sanz@gmail.com>\n"

# qtranslate-slug.php
msgid "Language selector"
msgstr "Selector de idioma"

# qtranslate-slug.php
msgid "Title:"
msgstr "Título:"

# qtranslate-slug.php
msgid "<p style=\"color:red\">This plugin requires qTranslate to be installed and activated.</p>"
msgstr "<p style=\"color:red\">Este plugin necesita qTranslate instalado y activado previamente.</p>"

# qtranslate-slug.php
msgid "Slug"
msgstr "Enlace permanente"

# qtranslate-slug.php
msgid "Show short name (en):"
msgstr "Mostrar nombre corto (en):"

# qtranslate-slug-settings-options.php
msgid "Post types"
msgstr "Post types"

# qtranslate-slug-settings-options.php
msgid "Taxonomies"
msgstr "Taxonomias"

# qtranslate-slug-settings-options.php
msgid "Slug (%s)"
msgstr "URL (%s)"

# qtranslate-slug-settings-options.php
msgid "<code>http://example.org/<u>%s</u>/some-%s/</code>"
msgstr "<code>http://ejemplo.org/<u>%s</u>/algun-%s/</code>"

# qtranslate-slug-settings-options.php
msgid "<code>http://example.org/<u>category</u>/some-category/</code>"
msgstr "<code>http://ejemplo.org/<u>categoria</u>/alguna-categoria/</code>"

# qtranslate-slug-settings-options.php
msgid "<code>http://example.org/<u>tag</u>/some-tag/</code>"
msgstr "<code>http://ejemplo.org/<u>etiqueta</u>/alguna-etiqueta/</code>"

# qtranslate-slug-settings.php
msgid "Qtranslate Slug options"
msgstr "Opciones de Qtranslate Slug"

# qtranslate-slug-settings.php
msgid "Slug options"
msgstr "Opciones de URL"

# qtranslate-slug-settings.php
msgid "Save Changes"
msgstr "Guardar cambios"

# qtranslate-slug-settings.php
msgid "Expecting a Numeric value! Please fix."
msgstr "Se espera un valor numérico! Por favor, corrígelo."

# qtranslate-slug-settings.php
msgid "Expecting comma separated numeric values! Please fix."
msgstr "Se esperan valores numéricos separados por coma! Por favor, corrígelo."

# qtranslate-slug-settings.php
msgid "Invalid email"
msgstr "E-mail incorrecto"

# qtranslate-slug-settings.php
msgid "This setting field cannot be empty! Please enter a valid email address."
msgstr "Este campo no puede estar vacío! Por favor introduce una dirección de e-mail válida."

# qtranslate-slug-settings.php
msgid "Please enter a valid email address."
msgstr "Por favor introduce una dirección de e-mail válida."

# qtranslate-slug-settings.php
msgid "upgrade now"
msgstr "actualizar ahora"

# qtranslate-slug.php
msgid "Please update your old data to the new system."
msgstr "Por favor actualiza tu antiguo sistema de datos al nuevo."

# qtranslate-slug-settings.php
msgid "Upgrade your data"
msgstr "Actualiza tus datos"

# qtranslate-slug-settings.php
msgid "There are slugs stored with old data system. Please upgrade your data pressing upgrade button:"
msgstr "Hay slugs almacenados en el antiguo sistema. Por favor actualiza tus datos aprentando el botón actualizar:"

# qtranslate-slug-settings.php
msgid "Sorry, some error happened. Refresh this page and try again please."
msgstr "Lo sentimos, algún tipo de error ha ocurrido. Por favor recarga esta página y prueba otra vez."

# qtranslate-slug-settings.php
msgid "Congratulations, your data has been upgraded, you are up to date."
msgstr "Felicidades, tus datos se han actualizado, ahora estás al día."

# qtranslate-slug-settings.php
msgid "One step more, select what type of slug is this: <strong>%s</strong>"
msgstr "Un paso más, selecction qué tipo de slug es este: <strong>%s</strong>"

# qtranslate-slug-settings.php
msgid "Post, Page or Custom post type"
msgstr "Entrada, Página o Custom post type"

# qtranslate-slug-settings.php
msgid "Category, tag or custom taxonomy"
msgstr "Categoria, tag o taxonomía"

# qtranslate-slug.php
msgid "This plugin requires at least <strong>Wordpress 3.3</strong> and <strong>Qtranslate(2.5.8 or newer)</strong>"
msgstr "Este plugin requiere al menos <strong>Wordpress 3.3</strong> y <strong>Qtranslate(2.5.8 o mayor)</strong>"

# qtranslate-slug-settings.php
msgid "If you activated previously the <a href=\"options-permalink.php\">pretty permalinks</a>, in this section you can translate the <abbr title=\"en inglés, Universal Resource Locator\">URLs</abbr> <strong>bases</strong> for <a href=\"http://codex.wordpress.org/Function_Reference/register_post_type#Arguments\">public</a> post_types, categories, tags and taxonomies."
msgstr "Si has activado previamente los <a href=\"options-permalink.php\">enlaces permanentes</a>, en esta sección podrás traducir las <strong>bases</strong> de las <abbr title=\"en inglés, Universal Resource Locator\">URLs</abbr> para post_types, categorías, etiquetas y taxonomias <a href=\"http://codex.wordpress.org/Function_Reference/register_post_type#Arguments\">públicas</a>."

# qtranslate-slug-settings.php
msgid "For example, the post_type <kbd>books</kbd>, in Spanish would be displayed as <code>http://example.org/es/libros/post-type-name/</code>. If you leave this blank will use the default option when you <a href=\"http://codex.wordpress.org/Function_Reference/register_post_type\">registered</a> the post_type."
msgstr "Por ejemplo, para el post_type  <kbd>books</kbd> en Español se mostraría como <code>http://example.org/es/libros/post-type-name/</code>. Si dejas esto en blanco se usará la opción predeterminada cuando <a href=\"http://codex.wordpress.org/Function_Reference/register_post_type\">registraste</a> el post_type."

# qtranslate-slug-settings.php
msgid "For example, the taxonomy <kbd>category</kbd>, in Spanish would be displayed as <code>http://example.org/es/categoria/taxonomy-name/</code>. If you leave this blank will use the default option when you <a href=\"http://codex.wordpress.org/Function_Reference/register_taxonomy\">registered</a> the taxonomy (if you previously setup a base permastruct for <u>categories</u> or <u>tags</u> in <a href=\"options-permalink.php\">permalinks</a> page, these bases will be overwritten by the translated ones)."
msgstr "Por ejemplo, la taxonomia <kbd>category</kbd>, en Español se mostraría como <code>http://example.org/es/categoria/taxonomy-name/</code>.  Si dejas esto en blanco se usará la opción predeterminada cuando <a href=\"http://codex.wordpress.org/Function_Reference/register_taxonomy\">registraste</a> la texonomia (si previamente configuraste la base de las estructuraas de <u>categorías</u> o <u>tags</u> en la página <a href=\"options-permalink.php\">enlaces permanentes</a>, estas bases serán reemplazadas por las traducidas)."

# Copyright (C) 2012 qTranslate slug
# This file is distributed under the same license as the qTranslate slug package.
msgid ""
msgstr ""
"Project-Id-Version: qTranslate slug\n"
"Report-Msgid-Bugs-To: http://wordpress.org/tag/qtranslate-slug\n"
"POT-Creation-Date: 2015-01-23 14:23-0000\n"
"PO-Revision-Date: 2015-01-23 15:26-0000\n"
"Last-Translator: Pedro Mendonça <ped.gaspar@gmail.com>\n"
"Language-Team: Pedro Mendonça <ped.gaspar@gmail.com>\n"
"Language: pt_PT\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.7.3\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Poedit-SourceCharset: UTF-8\n"
"X-Poedit-KeywordsList: __;_e;__ngettext;_n;__ngettext_noop;_n_noop;_x;_nx;"
"_nx_noop;_ex;esc_attr__;esc_attr_e;esc_attr_x;esc_html__;esc_html_e;esc_html_x;"
"_c;_nc\n"
"X-Poedit-Basepath: .\n"
"X-Poedit-SearchPath-0: .\n"
"X-Poedit-SearchPath-1: ..\n"

#: ../includes/class-qtranslate-slug-widget.php:11
msgid "Allows your visitors to choose a Language."
msgstr "Permite aos visitantes escolher o seu Idioma."

#: ../includes/class-qtranslate-slug-widget.php:12
msgid "Language selector"
msgstr "Selector de idioma"

#: ../includes/class-qtranslate-slug-widget.php:19
msgid "Language"
msgstr "Idioma"

#: ../includes/class-qtranslate-slug-widget.php:51
msgid "Title:"
msgstr "Título:"

#: ../includes/class-qtranslate-slug-widget.php:52
msgid "Hide Title:"
msgstr "Esconder título:"

#: ../includes/class-qtranslate-slug-widget.php:53
msgid "Display:"
msgstr "Mostrar:"

#: ../includes/class-qtranslate-slug-widget.php:54
msgid "Text only"
msgstr "Apenas texto"

#: ../includes/class-qtranslate-slug-widget.php:55
msgid "Image only"
msgstr "Apenas imagem"

#: ../includes/class-qtranslate-slug-widget.php:56
msgid "Text and Image"
msgstr "Texto e imagem"

#: ../includes/class-qtranslate-slug-widget.php:57
msgid "Dropdown Box"
msgstr "Caixa de selecção"

#: ../includes/class-qtranslate-slug-widget.php:58
msgid "Show short name (en):"
msgstr "Mostrar abreviatura (pt):"

#: ../includes/class-qtranslate-slug.php:413
msgid "Please update your old data to the new system."
msgstr "Por favor actualize os seus dados antigos para o novo sistema."

#: ../includes/class-qtranslate-slug.php:413
#: ../includes/qtranslate-slug-settings.php:29
msgid "upgrade now"
msgstr "actualizar agora"

#: ../includes/class-qtranslate-slug.php:427
msgid "or newer"
msgstr "ou mais recente"

#: ../includes/class-qtranslate-slug.php:432
msgid "This plugin requires at least %s and either %s, or %s, or %s"
msgstr "Este plugin requer no mínimo o %s e o %s, ou %s, ou %s"

#: ../includes/class-qtranslate-slug.php:432
msgid "More information about"
msgstr "Mais informações sobre"

#: ../includes/class-qtranslate-slug.php:1612
msgid "View all posts in %s"
msgstr "Ver todos os artigos em %s"

#: ../includes/class-qtranslate-slug.php:1739
msgid "Empty Term"
msgstr "Termo vazio"

#: ../includes/class-qtranslate-slug.php:1999
#: ../includes/class-qtranslate-slug.php:2000
#: ../includes/class-qtranslate-slug.php:2003
#: ../includes/class-qtranslate-slug.php:2541
msgid "Slug"
msgstr "URL"

#: ../includes/class-qtranslate-slug.php:2214
#: ../includes/class-qtranslate-slug.php:2233
#: ../includes/qtranslate-slug-settings-options.php:39
msgid "Slug (%s)"
msgstr "URL (%s)"

#: ../includes/class-qtranslate-slug.php:2400
#: ../includes/class-qtranslate-slug.php:2404
msgid "Name"
msgstr "Nome"

#: ../includes/class-qtranslate-slug.php:2542
msgid "Posts"
msgstr "Artigos"

#: ../includes/class-qtranslate-slug.php:2634
msgid "Languages"
msgstr "Idiomas"

#: ../includes/class-qtranslate-slug.php:2657
msgid "All languages"
msgstr "Todos os idiomas"

#: ../includes/qtranslate-slug-settings-options.php:14
msgid "Post types"
msgstr "Tipos de artigos"

#: ../includes/qtranslate-slug-settings-options.php:15
msgid "Taxonomies"
msgstr "Taxonomias"

#: ../includes/qtranslate-slug-settings-options.php:16
msgid "Styles"
msgstr "Estilos"

#: ../includes/qtranslate-slug-settings-options.php:63
msgid "Change styles type"
msgstr "﻿Alterar o tipo de estilos"

#: ../includes/qtranslate-slug-settings-options.php:65
msgid "adds a file (qts-default.css) to the theme's header."
msgstr "adiciona um ficheiro (qts-default.css) ao cabeçalho do tema."

#: ../includes/qtranslate-slug-settings-options.php:66
msgid ""
"adds a minified ( slighlty faster) file (qts-default.min.css) to the theme's "
"header."
msgstr ""
"adiciona um ficheiro minimizado (qts-default.min.css), ligeiramente mais "
"rápido, ao cabeçalho do tema."

#: ../includes/qtranslate-slug-settings-options.php:67
msgid "prints the styles directly into the theme's header."
msgstr "﻿exibe os estilos directamente no cabeçalho do tema."

#: ../includes/qtranslate-slug-settings-options.php:68
msgid "neither include not print the default style."
msgstr "nem incluir nem exibir o estilo padrão."

#: ../includes/qtranslate-slug-settings-options.php:73
msgid "file"
msgstr "ficheiro"

#: ../includes/qtranslate-slug-settings-options.php:74
msgid "minified"
msgstr "minimizado"

#: ../includes/qtranslate-slug-settings-options.php:75
msgid "inline"
msgstr "em linha"

#: ../includes/qtranslate-slug-settings-options.php:76
msgid "none"
msgstr "nenhum"

#: ../includes/qtranslate-slug-settings-options.php:106
#: ../includes/qtranslate-slug-settings-options.php:148
msgid "<code>http://example.org/<u>%s</u>/some-%s/</code>"
msgstr "<code>http://exemplo.org/<u>%s</u>/qualquer-%s/</code>"

#: ../includes/qtranslate-slug-settings-options.php:119
msgid "Categories"
msgstr "Categorias"

#: ../includes/qtranslate-slug-settings-options.php:120
msgid "<code>http://example.org/<u>category</u>/some-category/</code>"
msgstr "<code>http://exemplo.org/<u>categoria</u>/qualquer-categoria/</code>"

#: ../includes/qtranslate-slug-settings-options.php:130
msgid "Tags"
msgstr "Etiquetas"

#: ../includes/qtranslate-slug-settings-options.php:131
msgid "<code>http://example.org/<u>tag</u>/some-tag/</code>"
msgstr "<code>http://exemplo.org/<u>etiqueta</u>/qualquer-etiqueta/</code>"

#: ../includes/qtranslate-slug-settings-options.php:175
msgid "Qtranslate Settings - Contextual Help"
msgstr "Definições do Qtranslate - Ajuda contextual"

#: ../includes/qtranslate-slug-settings-options.php:176
msgid ""
"Contextual help goes here. You may want to use different html elements to "
"format your text as you want."
msgstr ""
"Isto é a ajuda contextual. Poderá utilizar diferentes elementos html para "
"formatar o seu texto como desejar."

#: ../includes/qtranslate-slug-settings.php:23
msgid "Upgrade your data"
msgstr "Actualize os seus dados"

#: ../includes/qtranslate-slug-settings.php:24
msgid ""
"There are slugs stored with old data system. Please upgrade your data pressing "
"upgrade button:"
msgstr ""
"Existem URLs com sistema de dados antigo. Por favor actualize os seus dados "
"através do botão actualizar:"

#: ../includes/qtranslate-slug-settings.php:77
msgid "Sorry, some error happened. Refresh this page and try again please."
msgstr ""
"Lamentavelmente mas ocorreu um erro. Por favor refresque esta página e tente "
"novamente."

#: ../includes/qtranslate-slug-settings.php:84
msgid "Congratulations, your data has been upgraded, you are up to date."
msgstr ""
"Parabéns, os seus dados foram actualizados e o sistema está agora actual."

#: ../includes/qtranslate-slug-settings.php:90
msgid "One step more, select what type of slug is this: <strong>%s</strong>"
msgstr "Um passo mais, seleccione que tipo de URL é este: <strong>%s</strong>"

#: ../includes/qtranslate-slug-settings.php:91
msgid "Post, Page or Custom post type"
msgstr "Artigo, página ou tipo de artigo personalizado"

#: ../includes/qtranslate-slug-settings.php:91
msgid "Category, tag or custom taxonomy"
msgstr "Categoria, etiqueta ou taxonomia personalizada"

#: ../includes/qtranslate-slug-settings.php:182
#: ../includes/qtranslate-slug-settings.php:322
msgid "Qtranslate Slug options"
msgstr "Opções do Qtranslate Slug"

#: ../includes/qtranslate-slug-settings.php:322
msgid "Slug options"
msgstr "Opções do URL"

#: ../includes/qtranslate-slug-settings.php:359
msgid ""
"For example, the post_type <kbd>books</kbd>, in Spanish would be displayed as "
"<code>http://example.org/es/libros/post-type-name/</code>. If you leave this "
"blank will use the default option when you <a href=\"http://codex.wordpress."
"org/Function_Reference/register_post_type\">registered</a> the post_type."
msgstr ""
"Por exemplo, o tipo de artigo <kbd>livros</kbd>, em português seria mostrado "
"como <code>http://exemplo.org/pt/livros/nome-de-tipo-de-artigo/</code>. Se "
"deixar isto em branco, será usada a opção por omissão <a href=\"http://codex."
"wordpress.org/Function_Reference/register_post_type\">registada</a> no tipo de "
"artigo."

#: ../includes/qtranslate-slug-settings.php:364
msgid ""
"For example, the taxonomy <kbd>category</kbd>, in Spanish would be displayed "
"as <code>http://example.org/es/categoria/taxonomy-name/</code>. If you leave "
"this blank will use the default option when you <a href=\"http://codex."
"wordpress.org/Function_Reference/register_taxonomy\">registered</a> the "
"taxonomy (if you previously setup a base permastruct for <u>categories</u> or "
"<u>tags</u> in <a href=\"options-permalink.php\">permalinks</a> page, these "
"bases will be overwritten by the translated ones)."
msgstr ""
"Por exemplo, a taxonomia <kbd>categoria</kbd>, em português seria mostrado "
"como <code>http://exemplo.org/pt/categoria/nome-de-taxonomia/</code>. Se "
"deixar isto em branco, será usada a opção por omissão <a href=\"http://codex."
"wordpress.org/Function_Reference/register_taxonomy\">registada</a> na "
"taxonomia (se previamente configurou a base das ligações permanentes para "
"<u>categorias</u> ou <u>etiquetas</u> na página <a href=\"options-permalink.php"
"\">ligações permanentes</a>, estas bases serão sobrepostas pelas traduzidas)."

#: ../includes/qtranslate-slug-settings.php:368
msgid "The default styles are very minimal, and you can include them or not."
msgstr "﻿Os estilos padrão são mínimos, pode incluí-los ou não."

#: ../includes/qtranslate-slug-settings.php:567
msgid ""
"If you activated previously the <a href=\"options-permalink.php\">pretty "
"permalinks</a>, in this section you can translate the <abbr title=\"en inglés, "
"Universal Resource Locator\">URLs</abbr> <strong>bases</strong> for <a href="
"\"http://codex.wordpress.org/Function_Reference/register_post_type#Arguments"
"\">public</a> post_types, categories, tags and taxonomies."
msgstr ""
"Se activou previamente as <a href=\"options-permalink.php\">ligações "
"permanentes</a>, nesta secção poderá traduzir as <strong>bases</strong> das "
"<abbr title=\"em inglês, Universal Resource Locator\">URLs</abbr> para tipos "
"de artigo, categorias, etiquetas e taxonomias <a href=\"http://codex.wordpress."
"org/Function_Reference/register_post_type#Arguments\">públicas</a>."

#: ../includes/qtranslate-slug-settings.php:586
msgid "If you selected \"none\", copy and use these styles as you see fit:"
msgstr "Se escolher \"nenhum\", copie e utilize estes estilos como entender:"

#: ../includes/qtranslate-slug-settings.php:589
msgid "Save Changes"
msgstr "Guardar alterações"

#: ../includes/qtranslate-slug-settings.php:642
msgid "Expecting a Numeric value! Please fix."
msgstr "É necessário um valor numérico! Por favor, corrija."

#: ../includes/qtranslate-slug-settings.php:655
msgid "Expecting comma separated numeric values"
msgstr "Valores numéricos separados por vírgulas"

#: ../includes/qtranslate-slug-settings.php:665
msgid "Expecting comma separated numeric values! Please fix."
msgstr ""
"São necessários valores numéricos separados por vírgulas! Por favor, corrija."

#: ../includes/qtranslate-slug-settings.php:690
msgid "Invalid email"
msgstr "Email incorrecto"

#: ../includes/qtranslate-slug-settings.php:692
msgid "This setting field cannot be empty! Please enter a valid email address."
msgstr ""
"Este campo não pode estar vazio! Por favor introduza um endereço de email "
"válido."

#: ../includes/qtranslate-slug-settings.php:700
msgid "Please enter a valid email address."
msgstr "Por favor introduza um endereço de email válido."

#: ../qtranslate-slug.php:150
msgid "Settings"
msgstr "Definições"
# Copyright (C) 2012 qTranslate slug
# This file is distributed under the same license as the qTranslate slug package.
msgid ""
msgstr ""
"Project-Id-Version: qTranslate slug 1.0\n"
"Report-Msgid-Bugs-To: http://wordpress.org/tag/qtranslate-slug\n"
"POT-Creation-Date: 2015-01-23 14:23-0000\n"
"PO-Revision-Date: 2015-01-23 14:23-0000\n"
"Last-Translator: Pedro Mendonça <ped.gaspar@gmail.com>\n"
"Language-Team: Carlos Sanz Garcia <carlos.sanz@gmail.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 1.7.3\n"
"X-Poedit-SourceCharset: UTF-8\n"
"X-Poedit-KeywordsList: __;_e;__ngettext;_n;__ngettext_noop;_n_noop;_x;_nx;"
"_nx_noop;_ex;esc_attr__;esc_attr_e;esc_attr_x;esc_html__;esc_html_e;"
"esc_html_x\n"
"X-Poedit-Basepath: .\n"
"X-Poedit-SearchPath-0: .\n"
"X-Poedit-SearchPath-1: ..\n"

#: ../includes/class-qtranslate-slug-widget.php:11
msgid "Allows your visitors to choose a Language."
msgstr ""

#: ../includes/class-qtranslate-slug-widget.php:12
msgid "Language selector"
msgstr ""

#: ../includes/class-qtranslate-slug-widget.php:19
msgid "Language"
msgstr ""

#: ../includes/class-qtranslate-slug-widget.php:51
msgid "Title:"
msgstr ""

#: ../includes/class-qtranslate-slug-widget.php:52
msgid "Hide Title:"
msgstr ""

#: ../includes/class-qtranslate-slug-widget.php:53
msgid "Display:"
msgstr ""

#: ../includes/class-qtranslate-slug-widget.php:54
msgid "Text only"
msgstr ""

#: ../includes/class-qtranslate-slug-widget.php:55
msgid "Image only"
msgstr ""

#: ../includes/class-qtranslate-slug-widget.php:56
msgid "Text and Image"
msgstr ""

#: ../includes/class-qtranslate-slug-widget.php:57
msgid "Dropdown Box"
msgstr ""

#: ../includes/class-qtranslate-slug-widget.php:58
msgid "Show short name (en):"
msgstr ""

#: ../includes/class-qtranslate-slug.php:413
msgid "Please update your old data to the new system."
msgstr ""

#: ../includes/class-qtranslate-slug.php:413
#: ../includes/qtranslate-slug-settings.php:29
msgid "upgrade now"
msgstr ""

#: ../includes/class-qtranslate-slug.php:427
msgid "or newer"
msgstr ""

#: ../includes/class-qtranslate-slug.php:432
msgid "This plugin requires at least %s and either %s, or %s, or %s"
msgstr ""

#: ../includes/class-qtranslate-slug.php:432
msgid "More information about"
msgstr ""

#: ../includes/class-qtranslate-slug.php:1612
msgid "View all posts in %s"
msgstr ""

#: ../includes/class-qtranslate-slug.php:1739
msgid "Empty Term"
msgstr ""

#: ../includes/class-qtranslate-slug.php:1999
#: ../includes/class-qtranslate-slug.php:2000
#: ../includes/class-qtranslate-slug.php:2003
#: ../includes/class-qtranslate-slug.php:2541
msgid "Slug"
msgstr ""

#: ../includes/class-qtranslate-slug.php:2214
#: ../includes/class-qtranslate-slug.php:2233
#: ../includes/qtranslate-slug-settings-options.php:39
msgid "Slug (%s)"
msgstr ""

#: ../includes/class-qtranslate-slug.php:2400
#: ../includes/class-qtranslate-slug.php:2404
msgid "Name"
msgstr ""

#: ../includes/class-qtranslate-slug.php:2542
msgid "Posts"
msgstr ""

#: ../includes/class-qtranslate-slug.php:2634
msgid "Languages"
msgstr ""

#: ../includes/class-qtranslate-slug.php:2657
msgid "All languages"
msgstr ""

#: ../includes/qtranslate-slug-settings-options.php:14
msgid "Post types"
msgstr ""

#: ../includes/qtranslate-slug-settings-options.php:15
msgid "Taxonomies"
msgstr ""

#: ../includes/qtranslate-slug-settings-options.php:16
msgid "Styles"
msgstr ""

#: ../includes/qtranslate-slug-settings-options.php:63
msgid "Change styles type"
msgstr ""

#: ../includes/qtranslate-slug-settings-options.php:65
msgid "adds a file (qts-default.css) to the theme's header."
msgstr ""

#: ../includes/qtranslate-slug-settings-options.php:66
msgid ""
"adds a minified ( slighlty faster) file (qts-default.min.css) to the theme's "
"header."
msgstr ""

#: ../includes/qtranslate-slug-settings-options.php:67
msgid "prints the styles directly into the theme's header."
msgstr ""

#: ../includes/qtranslate-slug-settings-options.php:68
msgid "neither include not print the default style."
msgstr ""

#: ../includes/qtranslate-slug-settings-options.php:73
msgid "file"
msgstr ""

#: ../includes/qtranslate-slug-settings-options.php:74
msgid "minified"
msgstr ""

#: ../includes/qtranslate-slug-settings-options.php:75
msgid "inline"
msgstr ""

#: ../includes/qtranslate-slug-settings-options.php:76
msgid "none"
msgstr ""

#: ../includes/qtranslate-slug-settings-options.php:106
#: ../includes/qtranslate-slug-settings-options.php:148
msgid "<code>http://example.org/<u>%s</u>/some-%s/</code>"
msgstr ""

#: ../includes/qtranslate-slug-settings-options.php:119
msgid "Categories"
msgstr ""

#: ../includes/qtranslate-slug-settings-options.php:120
msgid "<code>http://example.org/<u>category</u>/some-category/</code>"
msgstr ""

#: ../includes/qtranslate-slug-settings-options.php:130
msgid "Tags"
msgstr ""

#: ../includes/qtranslate-slug-settings-options.php:131
msgid "<code>http://example.org/<u>tag</u>/some-tag/</code>"
msgstr ""

#: ../includes/qtranslate-slug-settings-options.php:175
msgid "Qtranslate Settings - Contextual Help"
msgstr ""

#: ../includes/qtranslate-slug-settings-options.php:176
msgid ""
"Contextual help goes here. You may want to use different html elements to "
"format your text as you want."
msgstr ""

#: ../includes/qtranslate-slug-settings.php:23
msgid "Upgrade your data"
msgstr ""

#: ../includes/qtranslate-slug-settings.php:24
msgid ""
"There are slugs stored with old data system. Please upgrade your data pressing "
"upgrade button:"
msgstr ""

#: ../includes/qtranslate-slug-settings.php:77
msgid "Sorry, some error happened. Refresh this page and try again please."
msgstr ""

#: ../includes/qtranslate-slug-settings.php:84
msgid "Congratulations, your data has been upgraded, you are up to date."
msgstr ""

#: ../includes/qtranslate-slug-settings.php:90
msgid "One step more, select what type of slug is this: <strong>%s</strong>"
msgstr ""

#: ../includes/qtranslate-slug-settings.php:91
msgid "Post, Page or Custom post type"
msgstr ""

#: ../includes/qtranslate-slug-settings.php:91
msgid "Category, tag or custom taxonomy"
msgstr ""

#: ../includes/qtranslate-slug-settings.php:182
#: ../includes/qtranslate-slug-settings.php:322
msgid "Qtranslate Slug options"
msgstr ""

#: ../includes/qtranslate-slug-settings.php:322
msgid "Slug options"
msgstr ""

#: ../includes/qtranslate-slug-settings.php:359
msgid ""
"For example, the post_type <kbd>books</kbd>, in Spanish would be displayed as "
"<code>http://example.org/es/libros/post-type-name/</code>. If you leave this "
"blank will use the default option when you <a href=\"http://codex.wordpress."
"org/Function_Reference/register_post_type\">registered</a> the post_type."
msgstr ""

#: ../includes/qtranslate-slug-settings.php:364
msgid ""
"For example, the taxonomy <kbd>category</kbd>, in Spanish would be displayed "
"as <code>http://example.org/es/categoria/taxonomy-name/</code>. If you leave "
"this blank will use the default option when you <a href=\"http://codex."
"wordpress.org/Function_Reference/register_taxonomy\">registered</a> the "
"taxonomy (if you previously setup a base permastruct for <u>categories</u> or "
"<u>tags</u> in <a href=\"options-permalink.php\">permalinks</a> page, these "
"bases will be overwritten by the translated ones)."
msgstr ""

#: ../includes/qtranslate-slug-settings.php:368
msgid "The default styles are very minimal, and you can include them or not."
msgstr ""

#: ../includes/qtranslate-slug-settings.php:567
msgid ""
"If you activated previously the <a href=\"options-permalink.php\">pretty "
"permalinks</a>, in this section you can translate the <abbr title=\"en inglés, "
"Universal Resource Locator\">URLs</abbr> <strong>bases</strong> for <a href="
"\"http://codex.wordpress.org/Function_Reference/register_post_type#Arguments"
"\">public</a> post_types, categories, tags and taxonomies."
msgstr ""

#: ../includes/qtranslate-slug-settings.php:586
msgid "If you selected \"none\", copy and use these styles as you see fit:"
msgstr ""

#: ../includes/qtranslate-slug-settings.php:589
msgid "Save Changes"
msgstr ""

#: ../includes/qtranslate-slug-settings.php:642
msgid "Expecting a Numeric value! Please fix."
msgstr ""

#: ../includes/qtranslate-slug-settings.php:655
msgid "Expecting comma separated numeric values"
msgstr ""

#: ../includes/qtranslate-slug-settings.php:665
msgid "Expecting comma separated numeric values! Please fix."
msgstr ""

#: ../includes/qtranslate-slug-settings.php:690
msgid "Invalid email"
msgstr ""

#: ../includes/qtranslate-slug-settings.php:692
msgid "This setting field cannot be empty! Please enter a valid email address."
msgstr ""

#: ../includes/qtranslate-slug-settings.php:700
msgid "Please enter a valid email address."
msgstr ""

#: ../qtranslate-slug.php:150
msgid "Settings"
msgstr ""
<?php
/*
Plugin Name: qTranslate slug
Plugin URI: http://not-only-code.github.com/qtranslate-slug/
Description: Allows to define a slug for each language and some qTranslate bug fixes
Version: 1.1.16
Author: Carlos Sanz Garcia, Pedro Carvalho 
Author URI: http://github.com/not-only-code
*/


////////////////////////////////////////////////////////////////////////////////////////

if ( !function_exists('_debug') ):
function _debug( $message ) {
	   
	if ( WP_DEBUG === true ):
		 
		if ( is_array( $message ) || is_object( $message ) ) {
			
			error_log( print_r( $message, true ) );
			
		} else {
			
			error_log( $message );
		}
			 
	 endif;
}
endif;

////////////////////////////////////////////////////////////////////////////////////////



/**
 * Includes
 *
 * @since 1.1.8
 */
include_once(dirname(__FILE__).'/includes/class-qtranslate-slug-widget.php');
include_once(dirname(__FILE__).'/includes/class-qtranslate-slug.php');

////////////////////////////////////////////////////////////////////////////////////////



/**
 * Define Constants
 *
 * @since 1.0
 */
if (!defined("QTS_VERSION")) 		    define("QTS_VERSION", '1.1.12');
if (!defined("QTS_PREFIX")) 		    define("QTS_PREFIX", '_qts_');
if (!defined("QTS_PAGE_BASENAME")) 		define('QTS_PAGE_BASENAME', 'qtranslate-slug-settings');
if (!defined("QTS_OPTIONS_NAME")) 		define("QTS_OPTIONS_NAME", 'qts_options');
if (!defined("PHP_EOL"))				define("PHP_EOL", "\r\n");

////////////////////////////////////////////////////////////////////////////////////////



/**
 * Includes
 *
 * @since 1.0
 */
if ( is_admin() && !QtranslateSlug::block_activate() ) { // setting options page
	include_once(dirname(__FILE__).'/includes/qtranslate-slug-settings.php'); 
}

include_once(dirname(__FILE__).'/includes/termmeta-core.php'); // termmeta install and core functions

////////////////////////////////////////////////////////////////////////////////////////


	
/**
 * Init the plugin
 *
 * @since 1.0
 */	
global $qtranslate_slug;

$qtranslate_slug = new QtranslateSlug();

// plugin activation
register_activation_hook( __FILE__, array($qtranslate_slug, 'install') );

// plugin deactivation
register_deactivation_hook( __FILE__, array($qtranslate_slug, 'deactivate') );

// plugin uninstall
register_uninstall_hook( __FILE__, 'qts_uninstall' );

// plugin init
add_action('plugins_loaded', array($qtranslate_slug, 'init') );

////////////////////////////////////////////////////////////////////////////////////////

/**
 * Language Selector Code for templating
 *
 * @package Qtranslate Slug
 * @subpackage Core 
 * @since 1.0
 */
function qts_language_menu ($type = "text", $args = array()) {
	global $qtranslate_slug;
	
	$qtranslate_slug->language_menu($type, $args);
}

/**
 * Finds the translated slug of the given post by calling get_slug
 * @param int $id the post id
 * @param string $lang which language to look for
 * @since 1.1.13
 */ 

function qts_get_slug( $id, $lang ) {
	global $qtranslate_slug;
	return $qtranslate_slug->get_slug($id, $lang);
}


/**
 * Adds support for old plugin function
 * 
 * @package Qtranslate Slug
 * @subpackage Core
 * @since 1.1.5
 */
function qTranslateSlug_getSelfUrl ($lang = false) { // bad naming, I'll keep just in case
	return qts_get_url($lang);
}

function qts_get_url($lang = false) {
	global $qtranslate_slug;

	return $qtranslate_slug->get_current_url($lang);
}



/**
 * Add a "Settings" link to the plugins.php page for Qtranslate Slug
 *
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0 
 *
 * @return calls qts_show_msg()
 */
function qts_add_settings_link( $links, $file ) {
	
	if (QtranslateSlug::block_activate()) return $links;
	
	$this_plugin = plugin_basename( __FILE__ );
	if( $file == $this_plugin ) {
		$settings_link = "<a href=\"options-general.php?page=" . QTS_PAGE_BASENAME . "\">" . __( 'Settings', 'qts' ) . '</a>';
		array_unshift($links, $settings_link);
	}
	return $links;
}
add_filter( 'plugin_action_links', 'qts_add_settings_link', 10, 2 );



/**
 * Delete plugin stored data ( options, termmeta table and postmeta data )
 *
 * @package Qtranslate Slug
 * @subpackage Settings
 * @version 1.0 
 *
 */
function qts_uninstall() {
	global $q_config, $wpdb;
	
	// options
	delete_option(QTS_OPTIONS_NAME);
	delete_option('qts_version');
	
	// delete termmeta table
	$wpdb->query("DROP TABLE IF EXISTS $wpdb->termmeta");
	
	// delete postmeta data
	$meta_keys = array();
	foreach ($q_config['enabled_languages'] as $lang) $meta_keys[] = sprintf("_qts_slug_%s", $lang);
	$meta_keys = "'". implode( "','", $meta_keys ) . "'";
	$wpdb->query("DELETE from $wpdb->postmeta WHERE meta_key IN ($meta_keys)");	
}
=== Qtranslate Slug ===
Contributors: carlos_a_sanz, pedroghandi  
Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=SYC46KSLRC4Q8
Tags: qtranslate, slug, multilanguage, widget
Requires at least: 3.3
Tested up to: 4.2.4
Stable tag: 1.1.17
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html

Adds support for permalink translations to QTranslate-X since wordpress 3.0

== Description ==

[Qtranslate-X](http://wordpress.org/plugins/qtranslate-x/) is a nice plugin for Multilingual Websites. **Qtranslate Slug** is an addon to QTranslate, which adds support for permalinks translations.

1.1.17 fixes a dangerous Security Exploit. Please update right now!

= Requirements: =

* Wordpress 3.3 (PHP 5.4 and MySQL 5)
* mQtranslate 2.6.2.4 or Qtranslate 2.5.8 or qtranslate-x ( 2.9.1 )

= New in 1.1.17 =
* Hability to filter the position of the Metabox
* Fixed dangerous security exploit!

= New in 1.1.16 =
Minor fix for the language menu using qtranslate's function

= New in 1.1.15 =
* Fixes the duplicated hreflang links in <head>

= New in 1.1.14 =

The menu widget didn't allow the visitors to change to the default language if qtranslate-x was being used. So, adjusted the Language Menu widget to play nice with qtranslate-x. 
Hope to bring some nice changes that were made in the github repository in the next version. For now, enjoy.

= New in 1.1.13 =
== Thanks to returning @pedro-mendonca for these commits: ==
* Cleaned duplicated label in widget
* Bug fix in "Slug (%s)" string translation
* Changed text strings with no text-domain and with text-domain 'qtranlate' to text-domain 'qts'
* pot catalog updated with current strings, including last found is "More information about".
== Thanks to @johnclause for these : ==
* Convenience links in notice_dependences
* Menu compatibility with qTranslate-X
* Fixed extra characters in widget
### Thanks to vbkun for casting the much wanted function to get a slug based on an id and language
* Added a global qts_get_slug( $id, $lang)
### and sadly:
* removed the menu admin box until better implementation


See you next Version!


**Advice: If you're using a multisite installation, you will must activate qtranslate plugins by separately on each site.**

You can also check the [project website](http://not-only-code.github.com/qtranslate-slug/) hosted on [GitHub](http://not-only-code.github.com).
Thanks for use this plugin!

= Contributors =

* [Pedro de Carvalho](https://github.com/LC43/)
* [Risto Niinemets](https://github.com/RistoNiinemets)
* [Pedro Mendonça](https://github.com/pedro-mendonca)
* [codep0et](https://github.com/codep0et)
* [Giraldi Maggio](https://github.com/bedex78)
* [jinoOM](https://github.com/jinoOM)
* [Juanfran](https://github.com/juanfran-granados)
* [Arild](https://github.com/arildm)
* [Rafa Aguilar](https://github.com/rafitaFCB)
* [Bastian Heist](https://github.com/beheist)
* [John Clause](https://github.com/johnclause)


== Installation ==
**This plugins requires [Qtranslate](http://wordpress.org/extend/plugins/qtranslate/) or [mqTranslate](https://wordpress.org/plugins/mqtranslate/) installed previously, if not, it will not activate.**

1. Upload `qtranslate-slug` to the `/wp-content/plugins/` directory.
1. Activate the plugin through the 'Plugins' menu in WordPress.
1. That's all!

= Changing base permastructs =

1. In admin: navigate to *Settings/Slug options*.
1. Set the base permastructs for **post types** and **taxonomies** (If you setup a base permastruct for *categories* or *tags* in *Settings/Permalinks*, these will be overwritten by the translated ones).
1. Save settings and that's all!

== Frequently Asked Questions ==

= It works with posts and pages, but with other content type? =

This plugin allows to translate slugs of: posts, pages, custom post types, categories, tags and custom taxonomies.

= Do I have to configure anything? =

If you want to translate also the base permastructs (ex. *category*, *tag*, etc). Visit the plugin settings page in the admin *Settings/Slug options*

= How can i insert a language selector in my theme ? =

You can choose to:
* use **Qtranslate Slug Widget** in your sidebar.
* place in your template `<?php if (function_exists('qts_language_menu') ) qts_language_menu('text'); ?>`. Options are: `dropdown`, `text`, `image`, and `both`.

= Appears an error 404, what can i do? =

In the admin go to *Settings/Permalinks* or *Settings/Slug options* and save.

= I can't manage translations in Nav Menus. = 

That's because language selector metabox is hidden, if you are in admin *nav menus* screen, press the button **Screen options** (on top and right) and after, check the option *Languages*. It will appear a **Language** meta box on top of the left sidebar.

= How to get the current url in a specific language? =

You can use `qts_get_url()` or the awkwardly named `qTranslateSlug_getSelfUrl()` which is an alias for the first one.


== Screenshots ==

1. Edit page for: post / page / post_type, you can see the meta box for translated slugs on top and right.
2. Add new taxonomy page
3. Edit taxonomy page
4. Qtranslate Slug options page for translate base permastructs of post_types and taxonomies.

== Changelog ==


= New in Versions 1.1.12 =

* fixed warnings in settings
* replace qtranslate with our own for taxonomies

= New in Versions 1.1.10 and 1.1.11 =

* Fixing wrong commit to wp.org
* Clean deleted files 
= New in Version 1.1.9 =

Lots of bug fixes! Thanks again to everyone that contributed to this project, with commits, bug reports and suggestions.

* Compatibility with qtranslate-X! ( thanks @beheist, pull #85, fixing most of #80 )
* More updates to the portuguese translation ( thanks pedro-mendonca, pull #86)
* Corrected the link to language files ( thanks pedro-mendonca )
* Added translation for some hardcoded texts ( thanks pedro-mendonca )
* Corrected a link from 'qtranslate' to 'qts' language files ( thanks pedro-mendonca )
* Fixed taxonomies slugs ( thanks to [eirikv's bug report](https://wordpress.org/support/topic/categories-slug-dont-work) )
* Fixed many warnings ( thanks piffpaffpuff, issue #78 and to [pedrodu1](https://wordpress.org/support/topic/warnings-qtranslate-slugphp) )
* Changed the behaviour of "Quick Edit", from the wp forums [1](https://wordpress.org/support/topic/categories-tags-and-quick-edit-dont-show-in-admin) [2](https://wordpress.org/support/topic/quick-edit-inhibited-by-qtranslate-slug-with-wp-41-mqtranslate) ( thanks everyone!! )
* Fixed the menus! Now you can properly use one menu for every language. Use the dropdown section "Languages", and for each item, change the "Navigation Label" and "Title Attribute". Select "All languages", to make sure everything is awesome! All these features were a consequence of fixing all the warnings based on [Gery's bug report](https://wordpress.org/support/topic/qtranslate-slug-conflicting-with-ubermenu). 
* Minor fixes, etc. 


= New in Version 1.1.9 =

Lots of bug fixes! Thanks again to everyone that contributed to this project, with commits, bug reports and suggestions.

* Compatibility with qtranslate-X! ( thanks @beheist, pull #85, fixing most of #80 )
* More updates to the portuguese translation ( thanks pedro-mendonca, pull #86)
* Corrected the link to language files ( thanks pedro-mendonca )
* Added translation for some hardcoded texts ( thanks pedro-mendonca )
* Corrected a link from 'qtranslate' to 'qts' language files ( thanks pedro-mendonca )
* Fixed taxonomies slugs ( thanks to [eirikv's bug report](https://wordpress.org/support/topic/categories-slug-dont-work)
* Fixed many warnings ( thanks piffpaffpuff, issue #78 and to [pedrodu1](https://wordpress.org/support/topic/warnings-qtranslate-slugphp) )
* Changed the behaviour of "Quick Edit", from the wp forums [1](https://wordpress.org/support/topic/categories-tags-and-quick-edit-dont-show-in-admin) [2](https://wordpress.org/support/topic/quick-edit-inhibited-by-qtranslate-slug-with-wp-41-mqtranslate) ( thanks everyone!! )
* Fixed the menus! Now you can properly use one menu for every language. Use the dropdown section "Languages", and for each item, change the "Navigation Label" and "Title Attribute". Select "All languages", to make sure everything is awesome! All these features were a consequence of fixing all the warnings based on [Gery's bug report)[https://wordpress.org/support/topic/qtranslate-slug-conflicting-with-ubermenu). 
* Minor fixes, etc. 

See you next Version!


= 1.1.8 =

Many thanks to everyone that contributed to this update, for their commits, bug reports and for simply using it

* Portuguese translation and fixed some translation bugs  ( thanks pedro-mendonca )
* removed mqtranslate switcher widget hook
* Updated the plugin structure and coding style
* solve some conflicts with search and pagination queries
* Settings php errors, syntax indent and fixed settings assets url
* Change titles when there is a click on pagination on show all pages tab ( thanks juanfran-granados )
* Formatted dependency notice message ( thanks arildm )
* Updated the deprecated jquery 'live' function and solve php strict standards error ( thanks rafitaFCB )  
* Fixed error showing if PHP was newer than 5.3 ( thanks rafitaFCB )  
* Strict standard advise prevented ( thanks rafitaFCB )
* php notices are prevented in post edit, when using adding new translated tags  ( thanks rafitaFCB )
* fixed the hreflang issue! 'bout time!
* As discussed in issue #25, the flags are now img tags, intead of background-url.
* Added another option to include the css style in a minified file. ( and also showing in the option screen the styles we would use.)

= 1.1.7 = 
* removed styles from html elements and added options to use .css file or print inline styles
* fixed tag creation on post edit.
* fixed earlier bad post slug introduced in 1.1.6

= 1.1.6 =
* compatible with mqtranslate
* php5.4+ compatible

= 1.1.5 = 
* bugfixes

= 1.1 = 
* added multisite support
* fixed some parse url bugs
* fixed slug bases validation 

= 1.0 =
* **works** with any permalink combination and qtranslate mode.
* new branch, the plugin has been rewritten: now the code is commented and wrapped inside a class, much code has change and the performance has been increased (use caches).
* data system changed, no ID for slug type, then it don't needs install `qtrasnlate_slug` table. That means slugs now are stored on meta tables and installation creates a termmeta table with some new *core functions* to access/save data, based on [simple term meta](http://wordpress.org/extend/plugins/simple-term-meta/). Upgrade process when the plugin updates from older versions.
* the plugin generates translated slug automatically from title in empty cases.
* the plugin checks if the slug already exists (per each language and `post_type`/`taxonomy`), and adds a progressive number in this case. Works on ajax requests for example when new taxonomies are created in edit post page.
* possibility to translate the base of permastructs for *post_types* and *taxonomies*, uses [$wp_rewrite](http://codex.wordpress.org/Class_Reference/WP_Rewrite). New admin options page for save the base permastructs.
* added some filters, see in [other notes](http://wordpress.org/extend/plugins/qtranslate-slug/other_notes/).
* added plugin language textdomain (.pot file).
* updated **Language selector Widget**, and some new conventions like accessible functions for templating.
* some bug fixes.
* some Qtranslate patches.

= 0.9 =
* some wordpress qTranslate bug fixes
* adds a javascript solution for qTranslate Nav Menus

= 0.8 =
* added support por Categories
* added support por Tags
* added support por Taxonomies
* added support por Custom Post Types

= 0.7 = [Zapo](http://www.qianqin.de/qtranslate/forum/viewtopic.php?f=4&t=1049&start=50#p7499)
* added suport for qTranslate TLD domain mode (en: domain.com | fr: domain.fr) visit 

= 0.5 and 0.6 enhanched by Marco Del Percio =

== Upgrade Notice ==

= 1.0 =
Major version, the plugin has been rewritten. Better performance, and some enhancements.

= 0.9 =
This version fix some bugs and allow multilanguage in nav-menus.

= 0.8 =
A lot of slugs content allowed

= 0.7 =
This version allows TLD domain option for a different Qtranslate fork maded by Zappo


== Other notes ==

Plugin filters reference:

= qts_validate_post_slug =  
filter to process the post slug before is saved on the database.  
`args: $post (object), $slug (string), $lang (string)`

= qts_validate_term_slug =  
filter to process the term slug before is saved on the database.  
`args: $term (object), $slug (string), $lang (string)`

= qts_url_args =  
filter to process the entire url after it has been generated.  
`args: $url (string), $lang (string)`
 
= qts_permastruct =  
filter to process the permastruct, used for change the base.  
`args: $permastruct (string), $name (string)`


= Todo =

* detect Slug for each language and redirect accordingly in parse_query.
* expand qtranslate for translate attachment names and descriptions ( useful for galleries )
* translate other slugs like attachments.
* qtranslate integration with other plugins like Jigoshop, e-commerce, etc. Addapt **$wp_rewrite**.
= New in 1.1.17 =
* Fixed dangerous security exploit!
* Hability to filter the position of the Metabox

= New in 1.1.16 =
Minor fix for the language menu using qtranslate's function

= New in 1.1.15 =
* Fixes the duplicated hreflang links in <head>

= New in 1.1.14 =

The menu widget didn't allow the visitors to change to the default language if qtranslate-x was being used. So, adjusted the Language Menu widget to play nice with qtranslate-x. 
Hope to bring some nice changes that were made in the github repository in the next version. For now, enjoy.

= 1.1.13 =
== Thanks to returning @pedro-mendonca for these commits: ==
* Cleaned duplicated label in widget
* Bug fix in "Slug (%s)" string translation
* Changed text strings with no text-domain and with text-domain 'qtranlate' to text-domain 'qts'
* pot catalog updated with current strings, including last found is "More information about".
== Thanks to @johnclause for these : ==
* Convenience links in notice_dependences
* Menu compatibility with qTranslate-X
* Fixed extra characters in widget
== Thanks to vbkun for casting this much wanted function ==
* Added a global qts_get_slug( $id, $lang)
== and sadly: ==
* removed the menu admin box until better implementation

= 1.1.12 =

* fixed warnings in settings
* replace qtranslate with our own for taxonomies

= 1.1.10 and 1.1.11 =
* Fixing wrong commit to wp.org
* Clean deleted files

= 1.1.9  =

Lots of bug fixes! Thanks again to everyone that contributed to this project, with commits, bug reports and suggestions.

* Compatibility with qtranslate-X! ( thanks @beheist, pull #85, fixing most of #80 )
* More updates to the portuguese translation ( thanks pedro-mendonca, pull #86)
* Corrected the link to language files ( thanks pedro-mendonca )
* Added translation for some hardcoded texts ( thanks pedro-mendonca )
* Corrected a link from 'qtranslate' to 'qts' language files ( thanks pedro-mendonca )
* Fixed taxonomies slugs ( thanks to [eirikv's bug report](https://wordpress.org/support/topic/categories-slug-dont-work) )
* Fixed many warnings ( thanks piffpaffpuff, issue #78 and to [pedrodu1](https://wordpress.org/support/topic/warnings-qtranslate-slugphp) )
* Changed the behaviour of "Quick Edit", from the wp forums [1](https://wordpress.org/support/topic/categories-tags-and-quick-edit-dont-show-in-admin) [2](https://wordpress.org/support/topic/quick-edit-inhibited-by-qtranslate-slug-with-wp-41-mqtranslate) ( thanks everyone!! )
* Fixed the menus! Now you can properly use one menu for every language. Use the dropdown section "Languages", and for each item, change the "Navigation Label" and "Title Attribute". Select "All languages", to make sure everything is awesome! All these features were a consequence of fixing all the warnings based on [Gery's bug report](https://wordpress.org/support/topic/qtranslate-slug-conflicting-with-ubermenu). 
* Minor fixes, etc. 

See you next Version!

= 1.1.8 =

Many thanks to everyone that contributed to this update, both for their commits and bug reports )

* Portuguese translation and fixed some translation bugs  ( thanks pedro-mendonca )
* removed mqtranslate switcher widget hook
* Updated the plugin structure and coding style
* solve some conflicts with search and pagination queries
* Settings php errors, syntax indent and fixed settings assets url
* Change titles when there is a click on pagination on show all pages tab ( thanks juanfran-granados )
* Formatted dependency notice message ( thanks arildm )
* Updated the deprecated jquery 'live' function and solve php strict standards error ( thanks rafitaFCB )  
* Fixed error showing if PHP was newer than 5.3 ( thanks rafitaFCB )  
* Strict standard advise prevented ( thanks rafitaFCB )
* php notices are prevented in post edit, when using adding new translated tags  ( thanks rafitaFCB )
* fixed the hreflang issue! 'bout time!
* As discussed in issue #25, the flags are now img tags, intead of background-url.
* Added another option to include the css style in a minified file. ( and also showing in the option screen the styles we would use.)

= 1.1.7 = 
* removed styles from html elements and added options to use .css file or print inline styles
* fixed tag creation on post edit.
* fixed earlier bad post slug introduced in 1.1.6

= 1.1.6 =
* compatible with mqtranslate
* php5.4+ compatible

= 1.1.5 = 
* bugfixes

= 1.1 = 
* added multisite support
* fixed some parse url bugs
* fixed slug bases validation 

= 1.0 =
* new branch, the plugin has been rewrited: now the code is commented and wrapped inside a class, also all code has change and the performance has been increased.
* structural changes:
	* no ID for slug type, then don't install qtrasnlate_slug table.
	* slugs now are stored on meta tables, installation creates a termmeta table with some new 'core functions' to access/save data, based on [simple term meta](http://wordpress.org/extend/plugins/simple-term-meta/).
* some automation:
	* the plugin generates translated slug automatically from title in empty cases (like wordpress).
	* the plugin checks if the slug already exists (per each language and type / taxonomy), and adds a progressive number in this case (like wordpress).
	* works on ajax requests like creatig new taxonomies on edit post page.
* possibility to translate the base of permastructs for 'post_types' and 'taxonomies' (uses $wp_rewrite).
* added some filters:
	* 'qts_validate_post_slug' : args( $post (object), $slug (string), $lang (string) ) / filter to process the post slug before is saved on the database.
	* 'qts_validate_term_slug' : args( $term (object), $slug (string), $lang (string) ) / filter to process the term slug before is saved on the database.
	* 'qts_current_url' : args ( $url (string), $lang (string) ) / filter to process the entire url after it has been generated.
	* 'qts_permastruct' : args ( $permastruct (string), $name (string) ) / filter to process the permastruct, used for change the base.
* added plugin language textdomain (.pot file)
* new admin options page for save the base permastructs.
* import process when the plugin updates older versions.
* some bug fixes.
* some Qtranslate patches.

= 0.9 =
* some wordpress qTranslate bug fixes
* adds a javascript solution for qTranslate Nav Menus

= 0.8 =
* added support por Categories
* added support por Tags
* added support por Taxonomies
* added support por Custom Post Types

= 0.7 ( enhanced by Zapo (http://www.qianqin.de/qtranslate/forum/viewtopic.php?f=4&t=1049&start=50#p7499) ) =
* added suport for qTranslate TLD domain mode (en: domain.com | fr: domain.fr) visit 

= 0.5 and 0.6 enhanched by Marco Del Percio =