TranslatePress – Translate Multilingual sites - Version 1.1.4

Version Description

  • Filter to allow adding new language: 'trp_wp_languages'
  • Fixed issue with get_permalink() in ajax calls that was not returning the propper language
  • Adapted code to allow language based on a GET parameter
  • Fix some issues with language switcher and custom queries as well as take into account if subdirectory for default language is on
  • Fixed issue with js translation that was trimming numbers and other characters from strings when it shouldn't
Download this release

Release Info

Developer madalin.ungureanu
Plugin Icon 128x128 TranslatePress – Translate Multilingual sites
Version 1.1.4
Comparing to
See all releases

Code changes from version 1.1.3 to 1.1.4

assets/js/trp-editor-script.js CHANGED
@@ -36,12 +36,14 @@ function TRP_Editor(){
36
  /* pass on trp-view-as parameters to all links that also have preview parameter */
37
  if( typeof URL == 'function' && window.location.href.search("trp-view-as=") >= 0 && window.location.href.search("trp-view-as-nonce=") >= 0 ){
38
  var currentUrl = new URL(window.location.href);
39
- jQuery(select.form).append('<input type="hidden" name="trp-view-as" value="'+currentUrl.searchParams.get("trp-view-as")+'"/>');
40
- jQuery(select.form).append('<input type="hidden" name="trp-view-as-nonce" value="'+currentUrl.searchParams.get("trp-view-as-nonce")+'"/>');
41
- }
42
 
43
- select.form.action = link;
44
- select.form.submit();
 
 
 
45
  }
46
  };
47
 
36
  /* pass on trp-view-as parameters to all links that also have preview parameter */
37
  if( typeof URL == 'function' && window.location.href.search("trp-view-as=") >= 0 && window.location.href.search("trp-view-as-nonce=") >= 0 ){
38
  var currentUrl = new URL(window.location.href);
39
+ var trp_view_as = currentUrl.searchParams.get("trp-view-as");
40
+ link = _this.update_query_string('trp-view-as', trp_view_as, link );
 
41
 
42
+ var trp_view_as_nonce = currentUrl.searchParams.get("trp-view-as-nonce");
43
+ link = _this.update_query_string('trp-view-as-nonce', trp_view_as, link );
44
+ }
45
+ link = _this.update_query_string('trp-edit-translation', 'true', link );
46
+ window.location.href = link;
47
  }
48
  };
49
 
assets/js/trp-translate-dom-changes.js CHANGED
@@ -11,6 +11,7 @@ function TRP_Translator(){
11
  var wp_ajax_url = trp_data.trp_wp_ajax_url;
12
  var language_to_query;
13
  var except_characters = " \t\n\r  �.,/`~!@#$€£%^&*():;-_=+[]{}\\|?/<>1234567890'";
 
14
 
15
  /**
16
  * Ajax request to get translations for strings
@@ -133,7 +134,7 @@ function TRP_Translator(){
133
  var all_strings_length = all_strings.length;
134
  for (var j = 0; j < all_strings_length; j++ ) {
135
  if ( _this.trim( all_strings[j].textContent, except_characters ) != '' ) {
136
- strings.push({node: all_strings[j], original: _this.trim( all_strings[j].textContent, except_characters )});
137
  all_strings[j].textContent = '';
138
  }
139
  }
11
  var wp_ajax_url = trp_data.trp_wp_ajax_url;
12
  var language_to_query;
13
  var except_characters = " \t\n\r  �.,/`~!@#$€£%^&*():;-_=+[]{}\\|?/<>1234567890'";
14
+ var trim_characters = " \t\n\r  �\x0A\x0B" + "\302" + "\240";
15
 
16
  /**
17
  * Ajax request to get translations for strings
134
  var all_strings_length = all_strings.length;
135
  for (var j = 0; j < all_strings_length; j++ ) {
136
  if ( _this.trim( all_strings[j].textContent, except_characters ) != '' ) {
137
+ strings.push({node: all_strings[j], original: _this.trim( all_strings[j].textContent, trim_characters )});
138
  all_strings[j].textContent = '';
139
  }
140
  }
class-translate-press.php CHANGED
@@ -39,7 +39,7 @@ class TRP_Translate_Press{
39
  define( 'TRP_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
40
  define( 'TRP_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
41
  define( 'TRP_PLUGIN_SLUG', 'translatepress-multilingual' );
42
- define( 'TRP_PLUGIN_VERSION', '1.1.3' );
43
 
44
  $this->load_dependencies();
45
  $this->initialize_components();
@@ -90,7 +90,6 @@ class TRP_Translate_Press{
90
  $this->query = new TRP_Query( $this->settings->get_settings() );
91
  $this->machine_translator = new TRP_Machine_Translator( $this->settings->get_settings() );
92
  $this->translation_manager = new TRP_Translation_Manager( $this->settings->get_settings() );
93
-
94
  }
95
 
96
  /**
39
  define( 'TRP_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
40
  define( 'TRP_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
41
  define( 'TRP_PLUGIN_SLUG', 'translatepress-multilingual' );
42
+ define( 'TRP_PLUGIN_VERSION', '1.1.4' );
43
 
44
  $this->load_dependencies();
45
  $this->initialize_components();
90
  $this->query = new TRP_Query( $this->settings->get_settings() );
91
  $this->machine_translator = new TRP_Machine_Translator( $this->settings->get_settings() );
92
  $this->translation_manager = new TRP_Translation_Manager( $this->settings->get_settings() );
 
93
  }
94
 
95
  /**
includes/class-language-switcher.php CHANGED
@@ -25,6 +25,7 @@ class TRP_Language_Switcher{
25
  global $TRP_LANGUAGE;
26
  $TRP_LANGUAGE = $language;
27
  $this->add_cookie( $TRP_LANGUAGE );
 
28
  }
29
 
30
  /**
@@ -65,16 +66,9 @@ class TRP_Language_Switcher{
65
  * @return string Current language code.
66
  */
67
  private function get_current_language(){
68
- if ( isset( $_REQUEST['lang'] ) ){
69
- $language_code = sanitize_text_field( $_REQUEST['lang'] );
70
- if ( in_array( $language_code, $this->settings['translation-languages'] ) ) {
71
- return $language_code;
72
- }
73
- }else{
74
- $lang_from_url = $this->url_converter->get_lang_from_url_string( );
75
- if ( $lang_from_url != null ){
76
- return $lang_from_url;
77
- }
78
  }
79
 
80
  return $this->settings['default-language'];
@@ -274,6 +268,18 @@ class TRP_Language_Switcher{
274
  register_post_type( 'language_switcher', $args );
275
  }
276
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  /**
278
  * Prepare language switcher menu items.
279
  *
25
  global $TRP_LANGUAGE;
26
  $TRP_LANGUAGE = $language;
27
  $this->add_cookie( $TRP_LANGUAGE );
28
+ add_filter( 'get_user_option_metaboxhidden_nav-menus', array( $this, 'cpt_always_visible_in_menus' ), 10, 3 );
29
  }
30
 
31
  /**
66
  * @return string Current language code.
67
  */
68
  private function get_current_language(){
69
+ $lang_from_url = $this->url_converter->get_lang_from_url_string();
70
+ if ( $lang_from_url != null ){
71
+ return $lang_from_url;
 
 
 
 
 
 
 
72
  }
73
 
74
  return $this->settings['default-language'];
268
  register_post_type( 'language_switcher', $args );
269
  }
270
 
271
+ /**
272
+ * Makes the Language Switcher CPT always visible in Menus interface.
273
+ *
274
+ */
275
+ function cpt_always_visible_in_menus( $result, $option, $user )
276
+ {
277
+ if( in_array( 'add-post-type-language_switcher', $result ) )
278
+ $result = array_diff( $result, array( 'add-post-type-language_switcher' ) );
279
+
280
+ return $result;
281
+ }
282
+
283
  /**
284
  * Prepare language switcher menu items.
285
  *
includes/class-languages.php CHANGED
@@ -59,7 +59,7 @@ class TRP_Languages{
59
  }
60
  }
61
  $default = array( 'en_US' => array( 'language' => 'en_US', 'english_name'=> 'English (United States)', 'native_name' => 'English', 'iso' => array( 'en' ) ) );
62
- return $default + $this->wp_languages;
63
  }
64
 
65
  /**
59
  }
60
  }
61
  $default = array( 'en_US' => array( 'language' => 'en_US', 'english_name'=> 'English (United States)', 'native_name' => 'English', 'iso' => array( 'en' ) ) );
62
+ return apply_filters( 'trp_wp_languages', $default + $this->wp_languages );
63
  }
64
 
65
  /**
includes/class-translation-render.php CHANGED
@@ -527,9 +527,9 @@ class TRP_Translation_Render{
527
  }
528
 
529
  // pass the current language in forms where the action does not contain the language
530
- // based on this we're filtering wp_redirect to include the proper URL when returing to the current page.
531
  foreach ( $html->find('form') as $k => $row ){
532
- $row->innertext .= '<input type="hidden" name="trp-form-language" value="'. $TRP_LANGUAGE .'"/>';
533
  }
534
 
535
 
@@ -784,8 +784,9 @@ class TRP_Translation_Render{
784
  * @since 1.1.2
785
  */
786
  public function force_language_on_form_url_redirect( $location, $status ){
787
- if( isset( $_REQUEST['trp-form-language'] ) && !empty($_REQUEST['trp-form-language']) ){
788
- $form_language = esc_attr($_REQUEST['trp-form-language']);
 
789
  if ( ! $this->url_converter ) {
790
  $trp = TRP_Translate_Press::get_trp_instance();
791
  $this->url_converter = $trp->get_component('url_converter');
@@ -834,7 +835,7 @@ class TRP_Translation_Render{
834
  * @since 1.1.2
835
  */
836
  public function force_form_language_on_url_in_ajax( $output ){
837
- if ( TRP_Translation_Manager::is_ajax_on_frontend() && isset( $_REQUEST['trp-form-language'] ) && !empty( $_REQUEST['trp-form-language'] ) ) {
838
  $result = json_decode($output, TRUE);
839
  if ( json_last_error() === JSON_ERROR_NONE) {
840
  array_walk_recursive($result, array($this, 'callback_add_language_to_url'));
@@ -854,7 +855,8 @@ class TRP_Translation_Render{
854
  */
855
  function callback_add_language_to_url(&$item, $key){
856
  if ( filter_var($item, FILTER_VALIDATE_URL) !== FALSE ) {
857
- $form_language = esc_attr($_REQUEST['trp-form-language']);
 
858
  if ( ! $this->url_converter ) {
859
  $trp = TRP_Translate_Press::get_trp_instance();
860
  $this->url_converter = $trp->get_component('url_converter');
527
  }
528
 
529
  // pass the current language in forms where the action does not contain the language
530
+ // based on this we're filtering wp_redirect to include the proper URL when returning to the current page.
531
  foreach ( $html->find('form') as $k => $row ){
532
+ $row->innertext .= apply_filters( 'trp_form_inputs', '<input type="hidden" name="trp-form-language" value="'. $this->settings['url-slugs'][$TRP_LANGUAGE] .'"/>', $TRP_LANGUAGE, $this->settings['url-slugs'][$TRP_LANGUAGE] );
533
  }
534
 
535
 
784
  * @since 1.1.2
785
  */
786
  public function force_language_on_form_url_redirect( $location, $status ){
787
+ if( isset( $_REQUEST[ 'trp-form-language' ] ) && !empty($_REQUEST[ 'trp-form-language' ]) ){
788
+ $form_language_slug = esc_attr($_REQUEST[ 'trp-form-language' ]);
789
+ $form_language = array_search($form_language_slug, $this->settings['url-slugs']);
790
  if ( ! $this->url_converter ) {
791
  $trp = TRP_Translate_Press::get_trp_instance();
792
  $this->url_converter = $trp->get_component('url_converter');
835
  * @since 1.1.2
836
  */
837
  public function force_form_language_on_url_in_ajax( $output ){
838
+ if ( TRP_Translation_Manager::is_ajax_on_frontend() && isset( $_REQUEST[ 'trp-form-language' ] ) && !empty( $_REQUEST[ 'trp-form-language' ] ) ) {
839
  $result = json_decode($output, TRUE);
840
  if ( json_last_error() === JSON_ERROR_NONE) {
841
  array_walk_recursive($result, array($this, 'callback_add_language_to_url'));
855
  */
856
  function callback_add_language_to_url(&$item, $key){
857
  if ( filter_var($item, FILTER_VALIDATE_URL) !== FALSE ) {
858
+ $form_language_slug = esc_attr($_REQUEST[ 'trp-form-language' ]);
859
+ $form_language = array_search($form_language_slug, $this->settings['url-slugs']);
860
  if ( ! $this->url_converter ) {
861
  $trp = TRP_Translate_Press::get_trp_instance();
862
  $this->url_converter = $trp->get_component('url_converter');
includes/class-url-converter.php CHANGED
@@ -56,7 +56,7 @@ class TRP_Url_Converter {
56
  return $url;
57
  }
58
 
59
- if( is_customize_preview() || is_admin() )
60
  return $url;
61
 
62
 
@@ -67,13 +67,54 @@ class TRP_Url_Converter {
67
  $new_url .= '/' . ltrim( $path, '/' );
68
  }
69
 
70
- return apply_filters( 'trp_home_url', $new_url, $abs_home, $TRP_LANGUAGE, $path );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  }
72
 
73
  /**
74
  * Add Hreflang entries for each language to Header.
75
  */
76
  public function add_hreflang_to_head(){
 
77
  $languages = $this->settings['publish-languages'];
78
  if ( isset( $_GET['trp-edit-translation'] ) && $_GET['trp-edit-translation'] == 'preview' ) {
79
  $languages = $this->settings['translation-languages'];
@@ -126,15 +167,18 @@ class TRP_Url_Converter {
126
  $language = $TRP_LANGUAGE;
127
  }
128
 
129
-
130
  // if we have the homepage, we replace it with the filtered homepage that contains the language url.
131
- if( trailingslashit( $this->cur_page_url() ) == trailingslashit($this->get_abs_home()) ){
 
 
132
  $TRP_LANGUAGE = $language;
133
  $new_url = home_url();
134
  $TRP_LANGUAGE = $trp_language_copy;
135
  return $new_url . $trp_link_is_processed;
136
  }
137
 
 
 
138
 
139
  if ( empty( $url ) && is_object( $post ) && ( $post->ID != '0' ) && is_singular() ) {
140
  // if we have a $post we need to run the language switcher through get_permalink so we apply the correct slug that can be different.
@@ -158,6 +202,7 @@ class TRP_Url_Converter {
158
  } else {
159
  $new_url = str_replace($current_lang_root, $new_language_root, $url);
160
  }
 
161
  }
162
 
163
 
@@ -254,17 +299,19 @@ class TRP_Url_Converter {
254
 
255
  // We now have to see if the first part of the string is actually a language slug
256
  $lang = explode('/', $lang);
257
- if( $lang == false ){
258
- return null;
259
- }
260
- // If we have a language in the URL, the first element of the array should be it.
261
- $lang = $lang[0];
 
 
262
 
263
- // the lang slug != actual lang. So we need to do array_search so we don't end up with en instead of en_US
264
  if( isset($this->settings['url-slugs']) && in_array($lang, $this->settings['url-slugs']) ){
265
- return array_search($lang, $this->settings['url-slugs']);
266
  } else {
267
- return null;
268
  }
269
  }
270
 
56
  return $url;
57
  }
58
 
59
+ if( is_customize_preview() || $this->is_admin_request() )
60
  return $url;
61
 
62
 
67
  $new_url .= '/' . ltrim( $path, '/' );
68
  }
69
 
70
+ return apply_filters( 'trp_home_url', $new_url, $abs_home, $TRP_LANGUAGE, $path, $url );
71
+ }
72
+
73
+ /**
74
+ * Check if this is a request at the backend.
75
+ *
76
+ * @return bool true if is admin request, otherwise false.
77
+ */
78
+ public function is_admin_request() {
79
+ $current_url = $this->cur_page_url();
80
+ $admin_url = strtolower( admin_url() );
81
+
82
+ // we can't use wp_get_referer() It looks like it creates an infinite loop because it calls home_url() and we're filtering that
83
+ $referrer = '';
84
+ if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
85
+ $referrer = wp_unslash( $_REQUEST['_wp_http_referer'] );
86
+ } else if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
87
+ $referrer = wp_unslash( $_SERVER['HTTP_REFERER'] );
88
+ }
89
+
90
+
91
+ /**
92
+ * Check if this is a admin request. If true, it
93
+ * could also be a AJAX request from the frontend.
94
+ */
95
+ if ( 0 === strpos( $current_url, $admin_url ) ) {
96
+ /**
97
+ * Check if the user comes from a admin page.
98
+ */
99
+ if ( 0 === strpos( $referrer, $admin_url ) ) {
100
+ return true;
101
+ } else {
102
+ if ( function_exists( 'wp_doing_ajax' ) ) {
103
+ return ! wp_doing_ajax();
104
+ } else {
105
+ return ! ( defined( 'DOING_AJAX' ) && DOING_AJAX );
106
+ }
107
+ }
108
+ } else {
109
+ return false;
110
+ }
111
  }
112
 
113
  /**
114
  * Add Hreflang entries for each language to Header.
115
  */
116
  public function add_hreflang_to_head(){
117
+
118
  $languages = $this->settings['publish-languages'];
119
  if ( isset( $_GET['trp-edit-translation'] ) && $_GET['trp-edit-translation'] == 'preview' ) {
120
  $languages = $this->settings['translation-languages'];
167
  $language = $TRP_LANGUAGE;
168
  }
169
 
 
170
  // if we have the homepage, we replace it with the filtered homepage that contains the language url.
171
+ if( ( trailingslashit( $this->cur_page_url() ) == trailingslashit($this->get_abs_home()) )||
172
+ ( trailingslashit( $this->cur_page_url() ) == (trailingslashit($this->get_abs_home()) . $this->get_url_slug( $TRP_LANGUAGE ) . '/')) ){
173
+
174
  $TRP_LANGUAGE = $language;
175
  $new_url = home_url();
176
  $TRP_LANGUAGE = $trp_language_copy;
177
  return $new_url . $trp_link_is_processed;
178
  }
179
 
180
+ // make sure we have the original query
181
+ wp_reset_query();
182
 
183
  if ( empty( $url ) && is_object( $post ) && ( $post->ID != '0' ) && is_singular() ) {
184
  // if we have a $post we need to run the language switcher through get_permalink so we apply the correct slug that can be different.
202
  } else {
203
  $new_url = str_replace($current_lang_root, $new_language_root, $url);
204
  }
205
+ $new_url =apply_filters( 'trp_get_url_for_language', $new_url, $url, $language, $abs_home, $current_lang_root, $new_language_root );
206
  }
207
 
208
 
299
 
300
  // We now have to see if the first part of the string is actually a language slug
301
  $lang = explode('/', $lang);
302
+ if( $lang == false ){
303
+ return null;
304
+ }
305
+ // If we have a language in the URL, the first element of the array should be it.
306
+ $lang = $lang[0];
307
+
308
+ $lang = apply_filters( 'trp_get_lang_from_url_string', $lang, $url );
309
 
310
+ // the lang slug != actual lang. So we need to do array_search so we don't end up with en instead of en_US
311
  if( isset($this->settings['url-slugs']) && in_array($lang, $this->settings['url-slugs']) ){
312
+ return array_search($lang, $this->settings['url-slugs']);
313
  } else {
314
+ return null;
315
  }
316
  }
317
 
index.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: TranslatePress - Multilingual
4
  Plugin URI: https://translatepress.com/
5
  Description: Experience a better way of translating your WordPress site, with full support for WooCommerce and site builders.
6
- Version: 1.1.3
7
  Author: Cozmoslabs, Razvan Mocanu, Madalin Ungureanu, Cristophor Hurduban
8
  Author URI: https://cozmoslabs.com/
9
  License: GPL2
3
  Plugin Name: TranslatePress - Multilingual
4
  Plugin URI: https://translatepress.com/
5
  Description: Experience a better way of translating your WordPress site, with full support for WooCommerce and site builders.
6
+ Version: 1.1.4
7
  Author: Cozmoslabs, Razvan Mocanu, Madalin Ungureanu, Cristophor Hurduban
8
  Author URI: https://cozmoslabs.com/
9
  License: GPL2
partials/translation-manager.php CHANGED
@@ -53,7 +53,7 @@
53
  <div class="trp-controls-section">
54
  <div class="trp-controls-section-content">
55
  <form id="trp-language-switch-form" action="" method="GET">
56
- <select id="trp-language-select" onchange='trpEditor.change_language( this )'>
57
  <?php foreach ( $available_languages as $code => $language ) { ?>
58
  <option value="<?php echo $code; ?>" <?php echo ( $TRP_LANGUAGE == $code ) ? 'selected' : ''; ?>> <?php echo $language; ?> </option>
59
  <?php } ?>
53
  <div class="trp-controls-section">
54
  <div class="trp-controls-section-content">
55
  <form id="trp-language-switch-form" action="" method="GET">
56
+ <select id="trp-language-select" name='lang' onchange='trpEditor.change_language( this )'>
57
  <?php foreach ( $available_languages as $code => $language ) { ?>
58
  <option value="<?php echo $code; ?>" <?php echo ( $TRP_LANGUAGE == $code ) ? 'selected' : ''; ?>> <?php echo $language; ?> </option>
59
  <?php } ?>
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: cozmoslabs, razvan.mo, madalin.ungureanu, cristophor
3
  Donate link: https://www.cozmoslabs.com/
4
  Tags: translate, translation, multilingual, automatic translation, front-end translation, google translate, bilingual
5
  Requires at least: 3.1.0
6
- Tested up to: 4.9.1
7
- Stable tag: 1.1.3
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -45,11 +45,13 @@ Users with administrator rights have access to the following translate settings:
45
 
46
  TranslatePress - Multilingual has a range of premium [Add-ons](https://translatepress.com/?utm_source=wp.org&utm_medium=tp-description-page&utm_campaign=TPFree) that allow you to extend the power of the translation plugin:
47
 
48
- **Pro Add-ons** (available in the [PRO version](https://translatepress.com/?utm_source=wp.org&utm_medium=tp-description-page&utm_campaign=TPFree) only)
49
-
50
- * [Extra Languages](https://translatepress.com/?utm_source=wp.org&utm_medium=tp-description-page&utm_campaign=TPFree) - allows you to add an unlimited number of translation languages, with the possibility to publish languages later after you complete the translation
51
- * [SEO Pack](https://translatepress.com/?utm_source=wp.org&utm_medium=tp-description-page&utm_campaign=TPFree) - allows you to translate meta information (like page title, description, url slug, image alt tag, Twitter and Facebook Social Graph tags & more) for boosting your website's SEO and increase traffic
52
 
 
 
 
 
 
53
 
54
  = Website =
55
 
@@ -106,6 +108,12 @@ For more information please check out [TranslatePress documentation](https://tra
106
  6. Menu Language Switcher
107
 
108
  == Changelog ==
 
 
 
 
 
 
109
 
110
  = 1.1.3 =
111
  * Fix issue where the language switcher didn't work for BuddyPress pages
3
  Donate link: https://www.cozmoslabs.com/
4
  Tags: translate, translation, multilingual, automatic translation, front-end translation, google translate, bilingual
5
  Requires at least: 3.1.0
6
+ Tested up to: 4.9.2
7
+ Stable tag: 1.1.4
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
45
 
46
  TranslatePress - Multilingual has a range of premium [Add-ons](https://translatepress.com/?utm_source=wp.org&utm_medium=tp-description-page&utm_campaign=TPFree) that allow you to extend the power of the translation plugin:
47
 
48
+ **Pro Add-ons** (available in the [premium versions](https://translatepress.com/pricing/?utm_source=wp.org&utm_medium=tp-description-page&utm_campaign=TPFree) only)
 
 
 
49
 
50
+ * [Extra Languages](https://translatepress.com/docs/addons/seo-pack/?utm_source=wp.org&utm_medium=tp-description-page&utm_campaign=TPFree) - allows you to add an unlimited number of translation languages, with the possibility to publish languages later after you complete the translation
51
+ * [SEO Pack](https://translatepress.com/docs/addons/multiple-languages/?utm_source=wp.org&utm_medium=tp-description-page&utm_campaign=TPFree) - allows you to translate meta information (like page title, description, url slug, image alt tag, Twitter and Facebook Social Graph tags & more) for boosting your website's SEO and increase traffic
52
+ * [Translator Accounts](https://translatepress.com/docs/addons/translator-accounts/?utm_source=wp.org&utm_medium=tp-description-page&utm_campaign=TPFree) - create or allow existing users to translate the site without admin rights
53
+ * [Browse as User Role](https://translatepress.com/docs/addons/browse-as-role/?utm_source=wp.org&utm_medium=tp-description-page&utm_campaign=TPFree) - view and translate content that is visible only to a particular user role
54
+ * [Navigation Based on Language](https://translatepress.com/docs/addons/navigate-based-language/?utm_source=wp.org&utm_medium=tp-description-page&utm_campaign=TPFree) - configure and display different menu items for different languages
55
 
56
  = Website =
57
 
108
  6. Menu Language Switcher
109
 
110
  == Changelog ==
111
+ = 1.1.4 =
112
+ * Filter to allow adding new language: 'trp_wp_languages'
113
+ * Fixed issue with get_permalink() in ajax calls that was not returning the propper language
114
+ * Adapted code to allow language based on a GET parameter
115
+ * Fix some issues with language switcher and custom queries as well as take into account if subdirectory for default language is on
116
+ * Fixed issue with js translation that was trimming numbers and other characters from strings when it shouldn't
117
 
118
  = 1.1.3 =
119
  * Fix issue where the language switcher didn't work for BuddyPress pages