Polylang - Version 0.9.5

Version Description

(2012-11-13) =

  • The user can now choose the number of languages and strings translations to display
  • Add compatibility with the 'icl_object_id' function and ICL_LANGUAGE_CODE and ICL_LANGUAGE_NAME constants from the WPML API
  • Add 17 languages to the predefined list (automatic download and update of language files won't work)
  • Bug correction: post preview does not work when adding the language code to all urls
  • Bug correction: redirect to front page in default language when posting a comment on static front page
  • Bug correction: impossible to create terms with the same name in different languages
  • Bug correction: query string added by other plugins is erased when adding the language code to all urls
  • Bug correction: redirect erase 'POST' variables on homepage when adding the language code to all urls
  • Bug correction: English (en_US) loads rtl style when using a localized WordPress package with an rtl language
  • Bug correction: on some installation strings translations do not work with some special characters
  • Bug correction: incoming links are not redirected to canonical url when adding the language code to all urls and hiding the code for the default language
  • Bug correction: search form does not work in non default language when using permalinks without trailing slash
Download this release

Release Info

Developer Chouby
Plugin Icon 128x128 Polylang
Version 0.9.5
Comparing to
See all releases

Code changes from version 0.9.4 to 0.9.5

flags/es_VE.png ADDED
Binary file
flags/fa_AF.png ADDED
Binary file
flags/gd.png ADDED
Binary file
flags/hi_IN.png ADDED
Binary file
flags/kk.png ADDED
Binary file
flags/lo.png ADDED
Binary file
flags/mn.png ADDED
Binary file
flags/ms_MY.png ADDED
Binary file
flags/ne_NP.png ADDED
Binary file
flags/nn_NO.png ADDED
Binary file
flags/so_SO.png ADDED
Binary file
flags/su_ID.png ADDED
Binary file
flags/ta_LK.png ADDED
Binary file
flags/ur.png ADDED
Binary file
flags/uz_UZ.png ADDED
Binary file
flags/zh_HK.png ADDED
Binary file
include/admin-filters.php CHANGED
@@ -2,6 +2,8 @@
2
 
3
  // all modifications of the WordPress admin ui
4
  class Polylang_Admin_Filters extends Polylang_Admin_Base {
 
 
5
  function __construct() {
6
  parent::__construct();
7
 
@@ -96,6 +98,8 @@ class Polylang_Admin_Filters extends Polylang_Admin_Base {
96
  add_filter('wp_dropdown_cats', array(&$this, 'wp_dropdown_cats'));
97
  add_action('create_term', array(&$this, 'save_term'), 10, 3);
98
  add_action('edit_term', array(&$this, 'save_term'), 10, 3);
 
 
99
 
100
  // ajax response for edit term form
101
  add_action('wp_ajax_term_lang_choice', array(&$this,'term_lang_choice'));
@@ -486,6 +490,8 @@ class Polylang_Admin_Filters extends Polylang_Admin_Base {
486
  foreach ($terms as $term) {
487
  if ($term_id = $this->get_term($term->term_id, $_POST['post_lang_choice']))
488
  $newterms[] = (int) $term_id; // cast is important otherwise we get 'numeric' tags
 
 
489
  }
490
  wp_set_object_terms($post_id, $newterms, $tax);
491
  }
@@ -875,6 +881,17 @@ class Polylang_Admin_Filters extends Polylang_Admin_Base {
875
  }
876
  }
877
 
 
 
 
 
 
 
 
 
 
 
 
878
  // called when a category or post tag is deleted
879
  function delete_term($term_id) {
880
  $this->delete_term_language($term_id);
@@ -942,10 +959,14 @@ class Polylang_Admin_Filters extends Polylang_Admin_Base {
942
  if ('publish' != $new_status || 'publish' == $old_status || 'page' != $post->post_type || ! empty($post->post_parent))
943
  return;
944
 
945
- // get all the menus in the post language
946
- $menus = array();
947
  $lang = $this->get_post_language($post->ID);
948
  $menu_lang = get_option('polylang_nav_menus');
 
 
 
 
 
 
949
  foreach ($menu_lang as $menu) {
950
  if (isset($menu[$lang->slug]))
951
  $menus[] = $menu[$lang->slug];
2
 
3
  // all modifications of the WordPress admin ui
4
  class Polylang_Admin_Filters extends Polylang_Admin_Base {
5
+ private $pre_term_name; // used to store the term name before creating a slug if needed
6
+
7
  function __construct() {
8
  parent::__construct();
9
 
98
  add_filter('wp_dropdown_cats', array(&$this, 'wp_dropdown_cats'));
99
  add_action('create_term', array(&$this, 'save_term'), 10, 3);
100
  add_action('edit_term', array(&$this, 'save_term'), 10, 3);
101
+ add_filter('pre_term_name', array(&$this, 'pre_term_name'));
102
+ add_filter('pre_term_slug', array(&$this, 'pre_term_slug'), 10, 2);
103
 
104
  // ajax response for edit term form
105
  add_action('wp_ajax_term_lang_choice', array(&$this,'term_lang_choice'));
490
  foreach ($terms as $term) {
491
  if ($term_id = $this->get_term($term->term_id, $_POST['post_lang_choice']))
492
  $newterms[] = (int) $term_id; // cast is important otherwise we get 'numeric' tags
493
+ elseif (!is_wp_error($term_info = wp_insert_term($term->name, $tax))) // create the term in the correct language
494
+ $newterms[] = (int) $term_info['term_id'];
495
  }
496
  wp_set_object_terms($post_id, $newterms, $tax);
497
  }
881
  }
882
  }
883
 
884
+ // stores the term name for use in pre_term_slug
885
+ function pre_term_name($name) {
886
+ return $this->pre_term_name = $name;
887
+ }
888
+
889
+ // creates the term slug in case the term already exists in another language
890
+ function pre_term_slug($slug, $taxonomy) {
891
+ return !$slug && in_array($taxonomy, $this->taxonomies) && ($name = sanitize_title($this->pre_term_name)) && term_exists($name, $taxonomy) ?
892
+ $name.'-'.$this->get_language($_POST['term_lang_choice'])->slug : $slug;
893
+ }
894
+
895
  // called when a category or post tag is deleted
896
  function delete_term($term_id) {
897
  $this->delete_term_language($term_id);
959
  if ('publish' != $new_status || 'publish' == $old_status || 'page' != $post->post_type || ! empty($post->post_parent))
960
  return;
961
 
 
 
962
  $lang = $this->get_post_language($post->ID);
963
  $menu_lang = get_option('polylang_nav_menus');
964
+
965
+ if (!$lang || !$menu_lang)
966
+ return;
967
+
968
+ // get all the menus in the post language
969
+ $menus = array();
970
  foreach ($menu_lang as $menu) {
971
  if (isset($menu[$lang->slug]))
972
  $menus[] = $menu[$lang->slug];
include/admin.php CHANGED
@@ -8,20 +8,23 @@ class Polylang_Admin extends Polylang_Admin_Base {
8
  function __construct() {
9
  parent::__construct();
10
 
11
- // adds the about box the languages admin panel
12
- add_action('admin_init', array(&$this, 'admin_init'));
 
 
 
13
  }
14
 
15
- // adds the about box the languages admin panel
16
- function admin_init() {
17
  // test of $_GET['tab'] avoids displaying the automatically generated screen options on other tabs
18
- if (PLL_DISPLAY_ABOUT && (!isset($_GET['tab']) || $_GET['tab'] == 'lang'))
19
- add_meta_box('pll_about_box', __('About Polylang', 'polylang'), array(&$this, 'about'), 'settings_page_mlang', 'normal', 'high');
20
- }
 
21
 
22
- // displays the about metabox
23
- function about() {
24
- include(PLL_INC.'/about.php');
25
  }
26
 
27
  // used to update the translation when a language slug has been modified
@@ -290,6 +293,8 @@ class Polylang_Admin extends Polylang_Admin_Base {
290
  $wpdb->query("INSERT INTO $wpdb->termmeta (term_id, meta_key, meta_value) VALUES " . implode(',', $values));
291
 
292
  }
 
 
293
  break;
294
 
295
  default:
@@ -405,7 +410,7 @@ class Polylang_Admin extends Polylang_Admin_Base {
405
  global $wpdb;
406
  $terms = get_terms($this->taxonomies, array('get'=>'all', 'fields'=>'ids'));
407
  $tr_terms = $wpdb->get_col("SELECT term_id FROM $wpdb->termmeta WHERE meta_key = '_language'");
408
- $terms = array_unique(array_diff($terms, $tr_terms), SORT_NUMERIC); // array_unique to avoid duplicates if a term is in more than one taxonomy
409
 
410
  return apply_filters('pll_get_objects_with_no_lang', empty($posts) && empty($terms) ? false : array('posts' => $posts, 'terms' => $terms));
411
  }
8
  function __construct() {
9
  parent::__construct();
10
 
11
+ // adds screen options and the about box in the languages admin panel
12
+ add_action('load-settings_page_mlang', array(&$this, 'load_page'));
13
+
14
+ // saves per-page value in screen option
15
+ add_filter('set-screen-option', create_function('$s, $o, $v', 'return $v;'), 10, 3);
16
  }
17
 
18
+ // adds screen options and the about box in the languages admin panel
19
+ function load_page() {
20
  // test of $_GET['tab'] avoids displaying the automatically generated screen options on other tabs
21
+ if (PLL_DISPLAY_ABOUT && (!isset($_GET['tab']) || $_GET['tab'] == 'lang')) {
22
+ add_meta_box('pll_about_box', __('About Polylang', 'polylang'), create_function('',"include(PLL_INC.'/about.php');"), 'settings_page_mlang', 'normal');
23
+ add_screen_option('per_page', array('label' => __('Languages', 'polylang'), 'default' => 10, 'option' => 'pll_lang_per_page'));
24
+ }
25
 
26
+ if (isset($_GET['tab']) && $_GET['tab'] == 'strings')
27
+ add_screen_option('per_page', array('label' => __('Strings translations', 'polylang'), 'default' => 10, 'option' => 'pll_strings_per_page'));
 
28
  }
29
 
30
  // used to update the translation when a language slug has been modified
293
  $wpdb->query("INSERT INTO $wpdb->termmeta (term_id, meta_key, meta_value) VALUES " . implode(',', $values));
294
 
295
  }
296
+ wp_redirect('admin.php?page=mlang&tab=settings');
297
+ exit;
298
  break;
299
 
300
  default:
410
  global $wpdb;
411
  $terms = get_terms($this->taxonomies, array('get'=>'all', 'fields'=>'ids'));
412
  $tr_terms = $wpdb->get_col("SELECT term_id FROM $wpdb->termmeta WHERE meta_key = '_language'");
413
+ $terms = array_unique(array_diff($terms, $tr_terms)); // array_unique to avoid duplicates if a term is in more than one taxonomy
414
 
415
  return apply_filters('pll_get_objects_with_no_lang', empty($posts) && empty($terms) ? false : array('posts' => $posts, 'terms' => $terms));
416
  }
include/api.php CHANGED
@@ -15,15 +15,13 @@ function pll_current_language($args = 'slug') {
15
  // among the post and its translations, returns the id of the post which is in the language represented by $slug
16
  function pll_get_post($post_id, $slug = false) {
17
  global $polylang;
18
- $slug = $slug ? $slug : pll_current_language();
19
- return isset($polylang) && $slug ? $polylang->get_post($post_id, $slug) : null;
20
  }
21
 
22
  // among the term and its translations, returns the id of the term which is in the language represented by $slug
23
  function pll_get_term($term_id, $slug = false) {
24
  global $polylang;
25
- $slug = $slug ? $slug : pll_current_language();
26
- return isset($polylang) && $slug ? $polylang->get_term($term_id, $slug) : null;
27
  }
28
 
29
  // returns the home url in the right language
@@ -50,6 +48,24 @@ function pll_e($string) {
50
  }
51
 
52
  // compatibility with WPML API
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  if (!function_exists('icl_get_home_url')) {
54
  function icl_get_home_url() {
55
  return pll_home_url();
15
  // among the post and its translations, returns the id of the post which is in the language represented by $slug
16
  function pll_get_post($post_id, $slug = false) {
17
  global $polylang;
18
+ return isset($polylang) && ($slug = $slug ? $slug : pll_current_language()) ? $polylang->get_post($post_id, $slug) : null;
 
19
  }
20
 
21
  // among the term and its translations, returns the id of the term which is in the language represented by $slug
22
  function pll_get_term($term_id, $slug = false) {
23
  global $polylang;
24
+ return isset($polylang) && ($slug = $slug ? $slug : pll_current_language()) ? $polylang->get_term($term_id, $slug) : null;
 
25
  }
26
 
27
  // returns the home url in the right language
48
  }
49
 
50
  // compatibility with WPML API
51
+ add_action('pll_language_defined', 'pll_define_wpml_constants');
52
+
53
+ function pll_define_wpml_constants() {
54
+ if(!defined('ICL_LANGUAGE_CODE'))
55
+ define('ICL_LANGUAGE_CODE', pll_current_language());
56
+
57
+ if(!defined('ICL_LANGUAGE_NAME'))
58
+ define('ICL_LANGUAGE_NAME', pll_current_language('name'));
59
+ }
60
+
61
+ if (!function_exists('icl_object_id')) {
62
+ function icl_object_id($id, $type, $return_original_if_missing, $lang = false) {
63
+ global $polylang;
64
+ return isset($polylang) && ($lang = $lang ? $lang : pll_current_language()) && ($tr_id = $polylang->get_translation($type, $id, $lang)) ? $tr_id :
65
+ ($return_original_if_missing ? $id : null);
66
+ }
67
+ }
68
+
69
  if (!function_exists('icl_get_home_url')) {
70
  function icl_get_home_url() {
71
  return pll_home_url();
include/base.php CHANGED
@@ -10,6 +10,7 @@ abstract class Polylang_Base {
10
 
11
  // used to cache results
12
  private $languages_list = array();
 
13
  private $links = array();
14
 
15
  function __construct() {
@@ -62,13 +63,17 @@ abstract class Polylang_Base {
62
  }
63
 
64
  // returns the language by its id or its slug
65
- // Note: it seems that a numeric value is better for performance (3.2.1)
66
  function get_language($value) {
67
- $lang = is_object($value) ? $value :
68
- ((is_numeric($value) || (int) $value) ? get_term((int) $value, 'language') :
69
- (is_string($value) ? get_term_by('slug', $value , 'language') : // seems it is not cached in 3.2.1
70
- false));
71
- return isset($lang) && $lang && !is_wp_error($lang) ? $lang : false;
 
 
 
 
72
  }
73
 
74
  // saves translations for posts or terms
@@ -112,8 +117,9 @@ abstract class Polylang_Base {
112
 
113
  // returns an array of translations of a post or term
114
  function get_translations($type, $id) {
 
115
  // maybe_unserialize due to useless serialization in versions < 0.9
116
- return maybe_unserialize(get_metadata($type, $id, '_translations', true));
117
  }
118
 
119
  // store the post language in the database
10
 
11
  // used to cache results
12
  private $languages_list = array();
13
+ private $language = array();
14
  private $links = array();
15
 
16
  function __construct() {
63
  }
64
 
65
  // returns the language by its id or its slug
66
+ // Note: it seems that get_term_by slug is not cached (3.2.1)
67
  function get_language($value) {
68
+ if (is_object($value))
69
+ return $value;
70
+
71
+ if (isset($this->language[$value]))
72
+ return $this->language[$value];
73
+
74
+ $lang = (is_numeric($value) || (int) $value) ? get_term((int) $value, 'language') :
75
+ (is_string($value) ? get_term_by('slug', $value , 'language') : false);
76
+ return isset($lang) && $lang && !is_wp_error($lang) ? ($this->language[$value] = $lang) : false;
77
  }
78
 
79
  // saves translations for posts or terms
117
 
118
  // returns an array of translations of a post or term
119
  function get_translations($type, $id) {
120
+ $type = ($type == 'post' || in_array($type, $this->post_types)) ? 'post' : (($type == 'term' || in_array($type, $this->taxonomies)) ? 'term' : false);
121
  // maybe_unserialize due to useless serialization in versions < 0.9
122
+ return $type ? maybe_unserialize(get_metadata($type, $id, '_translations', true)) : array();
123
  }
124
 
125
  // store the post language in the database
include/core.php CHANGED
@@ -73,7 +73,11 @@ class Polylang_Core extends Polylang_base {
73
  add_filter('page_link', array(&$this, 'page_link'), 10, 2);
74
 
75
  // prevents redirection of the homepage
76
- add_filter('redirect_canonical', array(&$this, 'redirect_canonical'), 10, 2);
 
 
 
 
77
 
78
  // adds javascript at the end of the document
79
  if (!$GLOBALS['wp_rewrite']->using_permalinks() && PLL_SEARCH_FORM_JS)
@@ -201,7 +205,7 @@ class Polylang_Core extends Polylang_base {
201
  elseif ((is_single() || is_page() || (is_attachment() && PLL_MEDIA_SUPPORT)) && ( ($var = get_queried_object_id()) || ($var = get_query_var('p')) || ($var = get_query_var('page_id')) || ($var = get_query_var('attachment_id')) ))
202
  $lang = $this->get_post_language($var);
203
 
204
- else {
205
  foreach ($this->taxonomies as $taxonomy) {
206
  if ($var = get_query_var(get_taxonomy($taxonomy)->query_var))
207
  $lang = $this->get_term_language($var, $taxonomy);
@@ -217,10 +221,10 @@ class Polylang_Core extends Polylang_base {
217
  }
218
 
219
  // sets the language of comment
220
- // useful to redirect to correct post comment url when adding the language to all url
221
  function pre_comment_on_post($post_id) {
222
  $this->curlang = $this->get_post_language($post_id);
223
- $this->add_post_term_link_filters();
 
224
  }
225
 
226
  // sets the language when it is always included in the url
@@ -240,9 +244,13 @@ class Polylang_Core extends Polylang_base {
240
  // some PHP setups turn requests for / into /index.php in REQUEST_URI
241
  // thanks to Gonçalo Peres for pointing out the issue with queries unknown to WP
242
  // http://wordpress.org/support/topic/plugin-polylang-language-homepage-redirection-problem-and-solution-but-incomplete?replies=4#post-2729566
243
- if (str_replace('www.', '', home_url('/')) == trailingslashit((is_ssl() ? 'https://' : 'http://').str_replace('www.', '', $_SERVER['HTTP_HOST']).str_replace(array('index.php', '?'.$_SERVER['QUERY_STRING']), array('', ''), $_SERVER['REQUEST_URI'])))
244
- $this->home_requested();
245
-
 
 
 
 
246
  // $matches[1] is the slug of the requested language
247
  elseif ($matches)
248
  $this->curlang = $this->get_language($matches[1]);
@@ -252,6 +260,7 @@ class Polylang_Core extends Polylang_base {
252
  $this->curlang = $this->get_language($this->options['default_lang']);
253
 
254
  $GLOBALS['l10n']['pll_string'] = $this->mo_import($this->curlang);
 
255
  }
256
 
257
  // save the default locale before we start any language manipulation
@@ -316,26 +325,25 @@ class Polylang_Core extends Polylang_base {
316
  $this->add_language_filters();
317
 
318
  if (!($this->options['force_lang'] && $GLOBALS['wp_rewrite']->using_permalinks() && PLL_LANG_EARLY)) {
319
- if ($this->curlang->description != 'en_US') {
320
- // now we can load text domains with the right language
321
- $new_locale = get_locale();
322
- foreach ($this->list_textdomains as $textdomain)
323
- load_textdomain( $textdomain['domain'], str_replace($this->default_locale, $new_locale, $textdomain['mo']));
324
-
325
- // reinitializes wp_locale for weekdays and months, as well as for text direction
326
- unset($GLOBALS['wp_locale']);
327
- $GLOBALS['wp_locale'] = new WP_Locale();
328
- $GLOBALS['wp_locale']->text_direction = get_metadata('term', $this->curlang->term_id, '_rtl', true) ? 'rtl' : 'ltr';
329
-
330
- // translate labels of post types and taxonomies
331
- foreach ($GLOBALS['wp_taxonomies'] as $tax)
332
- $this->translate_labels($tax);
333
- foreach ($GLOBALS['wp_post_types'] as $pt)
334
- $this->translate_labels($pt);
335
- }
336
 
337
  // and finally load user defined strings
338
  $GLOBALS['l10n']['pll_string'] = $this->mo_import($this->curlang);
 
339
  }
340
  }
341
 
@@ -368,8 +376,10 @@ class Polylang_Core extends Polylang_base {
368
  // redirect to the home page in the right language
369
  // test to avoid crash if get_home_url returns something wrong
370
  // FIXME why this happens? http://wordpress.org/support/topic/polylang-crashes-1
371
- elseif (is_string($redirect = $this->get_home_url($this->curlang))) {
372
- wp_redirect($redirect);
 
 
373
  exit;
374
  }
375
  }
@@ -549,10 +559,42 @@ class Polylang_Core extends Polylang_base {
549
  }
550
 
551
  // prevents redirection of the homepage when using page on front
552
- function redirect_canonical($redirect_url, $requested_url) {
553
  return $requested_url == home_url('/') || strpos($requested_url, $this->page_link('', get_option('page_on_front'))) !== false ? false : $redirect_url;
554
  }
555
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
556
  // adds some javascript workaround knowing it's not perfect...
557
  function wp_print_footer_scripts() {
558
  // modifies the search form since filtering get_search_form won't work if the template uses searchform.php or the search form is hardcoded
@@ -792,7 +834,7 @@ class Polylang_Core extends Polylang_base {
792
  $ok = $trace['function'] == 'wp_nav_menu' ||
793
  // direct call from the theme
794
  (isset($trace['file']) && strpos($trace['file'], $theme) !== false &&
795
- in_array($trace['function'], array('home_url', 'bloginfo', 'get_bloginfo')) );
796
 
797
  if ($ok)
798
  return $this->get_home_url($this->curlang);
@@ -817,7 +859,7 @@ class Polylang_Core extends Polylang_base {
817
  if (!$is_search && $this->page_on_front && $id = $this->get_post($this->page_on_front, $language))
818
  return $this->home_urls[$language->slug][$is_search] = $this->page_link('', $id);
819
 
820
- return $this->home_urls[$language->slug][$is_search] = get_term_link($language, 'language');
821
  }
822
 
823
  // displays (or returns) the language switcher
73
  add_filter('page_link', array(&$this, 'page_link'), 10, 2);
74
 
75
  // prevents redirection of the homepage
76
+ add_filter('redirect_canonical', array(&$this, 'stop_redirect_canonical'), 10, 2);
77
+
78
+ // redirects incoming links to the proper URL when adding the language code to all urls
79
+ if ($this->options['force_lang'] && get_option('permalink_structure') && PLL_LANG_EARLY)
80
+ add_action('template_redirect', array(&$this, 'redirect_canonical'), 20); // after Wordpress redirect_canonical
81
 
82
  // adds javascript at the end of the document
83
  if (!$GLOBALS['wp_rewrite']->using_permalinks() && PLL_SEARCH_FORM_JS)
205
  elseif ((is_single() || is_page() || (is_attachment() && PLL_MEDIA_SUPPORT)) && ( ($var = get_queried_object_id()) || ($var = get_query_var('p')) || ($var = get_query_var('page_id')) || ($var = get_query_var('attachment_id')) ))
206
  $lang = $this->get_post_language($var);
207
 
208
+ elseif (isset($this->taxonomies)) {
209
  foreach ($this->taxonomies as $taxonomy) {
210
  if ($var = get_query_var(get_taxonomy($taxonomy)->query_var))
211
  $lang = $this->get_term_language($var, $taxonomy);
221
  }
222
 
223
  // sets the language of comment
 
224
  function pre_comment_on_post($post_id) {
225
  $this->curlang = $this->get_post_language($post_id);
226
+ add_filter('page_link', array(&$this, 'page_link'), 10, 2); // useful when posting a comment on static front page in non default language
227
+ $this->add_post_term_link_filters(); // useful to redirect to correct post comment url when adding the language to all url
228
  }
229
 
230
  // sets the language when it is always included in the url
244
  // some PHP setups turn requests for / into /index.php in REQUEST_URI
245
  // thanks to Gonçalo Peres for pointing out the issue with queries unknown to WP
246
  // http://wordpress.org/support/topic/plugin-polylang-language-homepage-redirection-problem-and-solution-but-incomplete?replies=4#post-2729566
247
+ if (str_replace('www.', '', home_url('/')) == trailingslashit((is_ssl() ? 'https://' : 'http://').str_replace('www.', '', $_SERVER['HTTP_HOST']).str_replace(array('index.php', '?'.$_SERVER['QUERY_STRING']), array('', ''), $_SERVER['REQUEST_URI']))) {
248
+ // take care to post preview http://wordpress.org/support/topic/static-frontpage-url-parameter-url-language-information
249
+ if (isset($_GET['preview']) && isset($_GET['p']) && $lg = $this->get_post_language($_GET['p']))
250
+ $this->curlang = $lg ? $lg : $this->get_language($this->options['default_lang']);
251
+ else
252
+ $this->home_requested();
253
+ }
254
  // $matches[1] is the slug of the requested language
255
  elseif ($matches)
256
  $this->curlang = $this->get_language($matches[1]);
260
  $this->curlang = $this->get_language($this->options['default_lang']);
261
 
262
  $GLOBALS['l10n']['pll_string'] = $this->mo_import($this->curlang);
263
+ do_action('pll_language_defined');
264
  }
265
 
266
  // save the default locale before we start any language manipulation
325
  $this->add_language_filters();
326
 
327
  if (!($this->options['force_lang'] && $GLOBALS['wp_rewrite']->using_permalinks() && PLL_LANG_EARLY)) {
328
+ // now we can load text domains with the right language
329
+ $new_locale = get_locale();
330
+ foreach ($this->list_textdomains as $textdomain)
331
+ load_textdomain( $textdomain['domain'], str_replace($this->default_locale, $new_locale, $textdomain['mo']));
332
+
333
+ // reinitializes wp_locale for weekdays and months, as well as for text direction
334
+ unset($GLOBALS['wp_locale']);
335
+ $GLOBALS['wp_locale'] = new WP_Locale();
336
+ $GLOBALS['wp_locale']->text_direction = get_metadata('term', $this->curlang->term_id, '_rtl', true) ? 'rtl' : 'ltr';
337
+
338
+ // translate labels of post types and taxonomies
339
+ foreach ($GLOBALS['wp_taxonomies'] as $tax)
340
+ $this->translate_labels($tax);
341
+ foreach ($GLOBALS['wp_post_types'] as $pt)
342
+ $this->translate_labels($pt);
 
 
343
 
344
  // and finally load user defined strings
345
  $GLOBALS['l10n']['pll_string'] = $this->mo_import($this->curlang);
346
+ do_action('pll_language_defined');
347
  }
348
  }
349
 
376
  // redirect to the home page in the right language
377
  // test to avoid crash if get_home_url returns something wrong
378
  // FIXME why this happens? http://wordpress.org/support/topic/polylang-crashes-1
379
+ // don't redirect if $_POST is not empty as it could break other plugins
380
+ // don't forget the query string which may be added by plugins even when permalinks are used
381
+ elseif (is_string($redirect = $this->get_home_url($this->curlang)) && empty($_POST)) {
382
+ wp_redirect(!$query && $_SERVER['QUERY_STRING'] ? $redirect.'?'. $_SERVER['QUERY_STRING'] : $redirect);
383
  exit;
384
  }
385
  }
559
  }
560
 
561
  // prevents redirection of the homepage when using page on front
562
+ function stop_redirect_canonical($redirect_url, $requested_url) {
563
  return $requested_url == home_url('/') || strpos($requested_url, $this->page_link('', get_option('page_on_front'))) !== false ? false : $redirect_url;
564
  }
565
 
566
+ // redirects incoming links to the proper URL when adding the language code to all urls
567
+ function redirect_canonical($requested_url = false, $do_redirect = true) {
568
+ if (!$requested_url)
569
+ $requested_url = (is_ssl() ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
570
+
571
+ if (is_single() || is_page()) {
572
+ global $post;
573
+ if (isset($post->ID) && in_array($post->post_type, $this->post_types))
574
+ $redirect_url = get_permalink((int)$post->ID);
575
+ }
576
+ elseif (is_category() || is_tag() || is_tax()) {
577
+ $obj = $GLOBALS['wp_query']->get_queried_object();
578
+ if (in_array($obj->taxonomy, $this->taxonomies))
579
+ $redirect_url = get_term_link((int)$obj->term_id, $obj->taxonomy);
580
+ }
581
+
582
+ if (!isset($redirect_url) || is_wp_error($redirect_url) || $redirect_url == $requested_url)
583
+ return false;
584
+
585
+ if ($do_redirect) {
586
+ // protect against chained redirects
587
+ if (!$this->redirect_canonical($redirect_url, false) ) {
588
+ wp_redirect($redirect_url, 301);
589
+ exit;
590
+ }
591
+ else
592
+ return false;
593
+ }
594
+
595
+ return $redirect_url;
596
+ }
597
+
598
  // adds some javascript workaround knowing it's not perfect...
599
  function wp_print_footer_scripts() {
600
  // modifies the search form since filtering get_search_form won't work if the template uses searchform.php or the search form is hardcoded
834
  $ok = $trace['function'] == 'wp_nav_menu' ||
835
  // direct call from the theme
836
  (isset($trace['file']) && strpos($trace['file'], $theme) !== false &&
837
+ in_array($trace['function'], array('home_url', 'get_home_url', 'bloginfo', 'get_bloginfo')) );
838
 
839
  if ($ok)
840
  return $this->get_home_url($this->curlang);
859
  if (!$is_search && $this->page_on_front && $id = $this->get_post($this->page_on_front, $language))
860
  return $this->home_urls[$language->slug][$is_search] = $this->page_link('', $id);
861
 
862
+ return $this->home_urls[$language->slug][$is_search] = trailingslashit(get_term_link($language, 'language'));
863
  }
864
 
865
  // displays (or returns) the language switcher
include/languages-form.php CHANGED
@@ -181,7 +181,7 @@ break;
181
  case 'settings': ?>
182
 
183
  <div class="form-wrap">
184
- <form id="options-lang" method="post" action="admin.php?page=mlang&tab=settings" class="validate">
185
  <?php wp_nonce_field('options-lang', '_wpnonce_options-lang');?>
186
  <input type="hidden" name="action" value="options" />
187
 
181
  case 'settings': ?>
182
 
183
  <div class="form-wrap">
184
+ <form id="options-lang" method="post" action="admin.php?page=mlang&tab=settings&noheader=true" class="validate">
185
  <?php wp_nonce_field('options-lang', '_wpnonce_options-lang');?>
186
  <input type="hidden" name="action" value="options" />
187
 
include/languages.php CHANGED
@@ -22,29 +22,40 @@ $languages = array(
22
  array('es', 'es_CL', 'Español'),
23
  array('es', 'es_ES', 'Español'),
24
  array('es', 'es_PE', 'Español'),
 
25
  array('et', 'et', 'Eesti'),
 
26
  array('fa', 'fa_IR', 'فارسی', 'rtl'),
27
  array('fi', 'fi', 'Suomi'),
28
  array('fo', 'fo', 'Føroyskt'),
29
  array('fr', 'fr_FR', 'Français'),
30
  array('fy', 'fy', 'Frysk'),
 
31
  array('gl', 'gl_ES', 'Galego'),
32
- array('he', 'he_IL', 'עברית', 'rtl'),
 
33
  array('hr', 'hr', 'Hrvatski'),
34
  array('hu', 'hu_HU', 'Magyar'),
35
  array('id', 'id_ID', 'Bahasa Indonesia'),
 
36
  array('it', 'it_IT', 'Italiano'),
37
  array('ja', 'ja', '日本語'),
38
  array('jv', 'jv_ID', 'Basa Jawa'),
39
  array('ka', 'ka_GE', 'ქართული'),
 
40
  array('ko', 'ko_KR', '한국어'),
41
  array('ku', 'ckb', 'کوردی', 'rtl'),
 
42
  array('lt', 'lt_LT', 'Lietuviškai'),
43
  array('lv', 'lv', 'Latviešu valoda'),
44
  array('mk', 'mk_MK', 'македонски јазик'),
 
 
45
  array('my', 'my_MM', 'ဗမာစာ'),
46
  array('nb', 'nb_NO', 'Norsk Bokmål'),
 
47
  array('nl', 'nl_NL', 'Nederlands'),
 
48
  array('pl', 'pl_PL', 'Polski'),
49
  array('pt', 'pt_BR', 'Português'),
50
  array('pt', 'pt_PT', 'Português'),
@@ -53,15 +64,21 @@ $languages = array(
53
  array('si', 'si_LK', 'සිංහල'),
54
  array('sk', 'sk_SK', 'Slovenčina'),
55
  array('sl', 'sl_SI', 'Slovenščina'),
 
56
  array('sq', 'sq', 'Shqip'),
57
  array('sr', 'sr_RS', 'Српски језик'),
 
58
  array('sv', 'sv_SE', 'Svenska'),
59
  array('ta', 'ta_LK', 'தமிழ்'),
60
  array('th', 'th', 'ไทย'),
61
  array('tr', 'tr_TR', 'Türkçe'),
62
  array('ug', 'ug_CN', 'Uyƣurqə'),
63
  array('uk', 'uk', 'Українська'),
 
 
 
64
  array('zh', 'zh_CN', '中文'),
 
65
  array('zh', 'zh_TW', '台灣'),
66
  );
67
  ?>
22
  array('es', 'es_CL', 'Español'),
23
  array('es', 'es_ES', 'Español'),
24
  array('es', 'es_PE', 'Español'),
25
+ array('es', 'es_VE', 'Español'),
26
  array('et', 'et', 'Eesti'),
27
+ array('fa', 'fa_AF', 'فارسی', 'rtl'),
28
  array('fa', 'fa_IR', 'فارسی', 'rtl'),
29
  array('fi', 'fi', 'Suomi'),
30
  array('fo', 'fo', 'Føroyskt'),
31
  array('fr', 'fr_FR', 'Français'),
32
  array('fy', 'fy', 'Frysk'),
33
+ array('gd', 'gd', 'Gàidhlig'),
34
  array('gl', 'gl_ES', 'Galego'),
35
+ array('he', 'he_IL', 'עברית', 'rtl'),
36
+ array('hi', 'hi_IN', 'हिन्दी'),
37
  array('hr', 'hr', 'Hrvatski'),
38
  array('hu', 'hu_HU', 'Magyar'),
39
  array('id', 'id_ID', 'Bahasa Indonesia'),
40
+ array('is', 'is_IS', 'Íslenska'),
41
  array('it', 'it_IT', 'Italiano'),
42
  array('ja', 'ja', '日本語'),
43
  array('jv', 'jv_ID', 'Basa Jawa'),
44
  array('ka', 'ka_GE', 'ქართული'),
45
+ array('kk', 'kk', 'Қазақ тілі'),
46
  array('ko', 'ko_KR', '한국어'),
47
  array('ku', 'ckb', 'کوردی', 'rtl'),
48
+ array('lo', 'lo', 'ພາສາລາວ'),
49
  array('lt', 'lt_LT', 'Lietuviškai'),
50
  array('lv', 'lv', 'Latviešu valoda'),
51
  array('mk', 'mk_MK', 'македонски јазик'),
52
+ array('mn', 'mn', 'Монгол хэл'),
53
+ array('ms', 'ms_MY', 'Bahasa Melayu'),
54
  array('my', 'my_MM', 'ဗမာစာ'),
55
  array('nb', 'nb_NO', 'Norsk Bokmål'),
56
+ array('ne', 'ne_NP', 'नेपाली'),
57
  array('nl', 'nl_NL', 'Nederlands'),
58
+ array('nn', 'nn_NO', 'Norsk Nynorsk'),
59
  array('pl', 'pl_PL', 'Polski'),
60
  array('pt', 'pt_BR', 'Português'),
61
  array('pt', 'pt_PT', 'Português'),
64
  array('si', 'si_LK', 'සිංහල'),
65
  array('sk', 'sk_SK', 'Slovenčina'),
66
  array('sl', 'sl_SI', 'Slovenščina'),
67
+ array('so', 'so_SO', 'Af-Soomaali'),
68
  array('sq', 'sq', 'Shqip'),
69
  array('sr', 'sr_RS', 'Српски језик'),
70
+ array('su', 'su_ID', 'Basa Sunda'),
71
  array('sv', 'sv_SE', 'Svenska'),
72
  array('ta', 'ta_LK', 'தமிழ்'),
73
  array('th', 'th', 'ไทย'),
74
  array('tr', 'tr_TR', 'Türkçe'),
75
  array('ug', 'ug_CN', 'Uyƣurqə'),
76
  array('uk', 'uk', 'Українська'),
77
+ array('ur', 'ur', 'اردو', 'rtl'),
78
+ array('uz', 'uz_UZ', 'Oʻzbek'),
79
+ array('vi', 'vi', 'Tiếng Việt'),
80
  array('zh', 'zh_CN', '中文'),
81
+ array('zh', 'zh_HK', '香港'),
82
  array('zh', 'zh_TW', '台灣'),
83
  );
84
  ?>
include/list-table.php CHANGED
@@ -69,7 +69,7 @@ class Polylang_List_Table extends WP_List_Table {
69
  */
70
 
71
  function prepare_items($data = array()) {
72
- $per_page = 10; // 10 languages per page
73
  $columns = $this->get_columns();
74
  $hidden = array();
75
  $sortable = $this->get_sortable_columns();
@@ -106,7 +106,7 @@ class Polylang_String_Table extends WP_List_Table {
106
  }
107
 
108
  function column_default($item, $column_name) {
109
- return $item[$column_name];
110
  }
111
 
112
  function column_translations($item) {
@@ -115,11 +115,11 @@ class Polylang_String_Table extends WP_List_Table {
115
  $input_type = $item['multiline'] ?
116
  '<textarea name="translation[%1$s][%2$s]" id="%1$s-%2$s">%4$s</textarea>' :
117
  '<input name="translation[%1$s][%2$s]" id="%1$s-%2$s" value="%4$s" />';
118
- $out .= sprintf('<div class="translation"><label for="%1$s-%2$s">%3$s</label>'.$input_type.'</div>',
119
  esc_attr($key),
120
  esc_attr($item['row']),
121
  esc_html($key),
122
- $item['multiline'] ? esc_textarea($translation) : esc_html($translation));
123
  }
124
  return $out;
125
  }
@@ -140,7 +140,7 @@ class Polylang_String_Table extends WP_List_Table {
140
  }
141
 
142
  function prepare_items($data = array()) {
143
- $per_page = 10; // 10 strings per page
144
  $columns = $this->get_columns();
145
  $hidden = array();
146
  $sortable = $this->get_sortable_columns();
69
  */
70
 
71
  function prepare_items($data = array()) {
72
+ $per_page = $this->get_items_per_page('pll_lang_per_page');
73
  $columns = $this->get_columns();
74
  $hidden = array();
75
  $sortable = $this->get_sortable_columns();
106
  }
107
 
108
  function column_default($item, $column_name) {
109
+ return $column_name == 'string' ? format_to_edit($item[$column_name]) : $item[$column_name]; // don't interpret special chars for the string column
110
  }
111
 
112
  function column_translations($item) {
115
  $input_type = $item['multiline'] ?
116
  '<textarea name="translation[%1$s][%2$s]" id="%1$s-%2$s">%4$s</textarea>' :
117
  '<input name="translation[%1$s][%2$s]" id="%1$s-%2$s" value="%4$s" />';
118
+ $out .= sprintf('<div class="translation"><label for="%1$s-%2$s">%3$s</label>'.$input_type.'</div>'."\n",
119
  esc_attr($key),
120
  esc_attr($item['row']),
121
  esc_html($key),
122
+ format_to_edit($translation)); // don't interpret special chars
123
  }
124
  return $out;
125
  }
140
  }
141
 
142
  function prepare_items($data = array()) {
143
+ $per_page = $this->get_items_per_page('pll_strings_per_page');
144
  $columns = $this->get_columns();
145
  $hidden = array();
146
  $sortable = $this->get_sortable_columns();
include/widget.php CHANGED
@@ -9,7 +9,7 @@ class Polylang_Widget extends WP_Widget {
9
  // displays the widget
10
  function widget($args, $instance) {
11
  global $polylang;
12
- if (!(isset($polylang) && $polylang->get_languages_list()))
13
  return;
14
 
15
  extract($args);
@@ -22,7 +22,7 @@ class Polylang_Widget extends WP_Widget {
22
  echo $before_title . $title . $after_title;
23
  if (!$dropdown)
24
  echo "<ul>\n";
25
- $polylang->the_languages($instance);
26
  if (!$dropdown)
27
  echo "</ul>\n";
28
  echo "$after_widget\n";
9
  // displays the widget
10
  function widget($args, $instance) {
11
  global $polylang;
12
+ if (!(isset($polylang) && $polylang->get_languages_list() && $list = $polylang->the_languages(array_merge($instance, array('echo' => 0)))))
13
  return;
14
 
15
  extract($args);
22
  echo $before_title . $title . $after_title;
23
  if (!$dropdown)
24
  echo "<ul>\n";
25
+ echo $list;
26
  if (!$dropdown)
27
  echo "</ul>\n";
28
  echo "$after_widget\n";
polylang.php CHANGED
@@ -2,9 +2,11 @@
2
  /*
3
  Plugin Name: Polylang
4
  Plugin URI: http://wordpress.org/extend/plugins/polylang/
5
- Version: 0.9.4
6
  Author: F. Demarle
7
  Description: Adds multilingual capability to Wordpress
 
 
8
  */
9
 
10
  /* Copyright 2011-2012 F. Demarle
@@ -24,7 +26,7 @@ Description: Adds multilingual capability to Wordpress
24
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25
  */
26
 
27
- define('POLYLANG_VERSION', '0.9.4');
28
  define('PLL_MIN_WP_VERSION', '3.1');
29
 
30
  define('POLYLANG_DIR', dirname(__FILE__)); // our directory
2
  /*
3
  Plugin Name: Polylang
4
  Plugin URI: http://wordpress.org/extend/plugins/polylang/
5
+ Version: 0.9.5
6
  Author: F. Demarle
7
  Description: Adds multilingual capability to Wordpress
8
+ Text Domain: polylang
9
+ Domain Path: /languages
10
  */
11
 
12
  /* Copyright 2011-2012 F. Demarle
26
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27
  */
28
 
29
+ define('POLYLANG_VERSION', '0.9.5');
30
  define('PLL_MIN_WP_VERSION', '3.1');
31
 
32
  define('POLYLANG_DIR', dirname(__FILE__)); // our directory
readme.txt CHANGED
@@ -4,7 +4,8 @@ Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_i
4
  Tags: multilingual, bilingual, translate, translation, language, multilanguage, i18n, international, l10n, localization
5
  Requires at least: 3.1
6
  Tested up to: 3.4.2
7
- Stable tag: 0.9.4
 
8
 
9
  Polylang adds multilingual content management support to WordPress.
10
 
@@ -92,6 +93,21 @@ Every suggestions are welcome.
92
 
93
  == Changelog ==
94
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  = 0.9.4 (2012-10-23) =
96
 
97
  * Add Afrikaans translation contributed by [Kobus Joubert](http://translate3d.com/)
4
  Tags: multilingual, bilingual, translate, translation, language, multilanguage, i18n, international, l10n, localization
5
  Requires at least: 3.1
6
  Tested up to: 3.4.2
7
+ Stable tag: 0.9.5
8
+ License: GPLv2 or later
9
 
10
  Polylang adds multilingual content management support to WordPress.
11
 
93
 
94
  == Changelog ==
95
 
96
+ = 0.9.5 (2012-11-13) =
97
+
98
+ * The user can now choose the number of languages and strings translations to display
99
+ * Add compatibility with the 'icl_object_id' function and ICL_LANGUAGE_CODE and ICL_LANGUAGE_NAME constants from the WPML API
100
+ * Add 17 languages to the predefined list (automatic download and update of language files won't work)
101
+ * Bug correction: post preview does not work when adding the language code to all urls
102
+ * Bug correction: redirect to front page in default language when posting a comment on static front page
103
+ * Bug correction: impossible to create terms with the same name in different languages
104
+ * Bug correction: query string added by other plugins is erased when adding the language code to all urls
105
+ * Bug correction: redirect erase 'POST' variables on homepage when adding the language code to all urls
106
+ * Bug correction: English (en_US) loads rtl style when using a localized WordPress package with an rtl language
107
+ * Bug correction: on some installation strings translations do not work with some special characters
108
+ * Bug correction: incoming links are not redirected to canonical url when adding the language code to all urls and hiding the code for the default language
109
+ * Bug correction: search form does not work in non default language when using permalinks without trailing slash
110
+
111
  = 0.9.4 (2012-10-23) =
112
 
113
  * Add Afrikaans translation contributed by [Kobus Joubert](http://translate3d.com/)