Polylang - Version 0.1

Version Description

  • Initial release
Download this release

Release Info

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

Version 0.1

Files changed (13) hide show
  1. add-term-form.php +11 -0
  2. admin.php +450 -0
  3. base.php +62 -0
  4. edit-term-form.php +74 -0
  5. languages-form.php +117 -0
  6. list-table.php +100 -0
  7. polylang-fr_FR.mo +0 -0
  8. polylang-fr_FR.po +172 -0
  9. polylang.php +654 -0
  10. post-metabox.php +40 -0
  11. readme.txt +76 -0
  12. uninstall.php +36 -0
  13. widget.php +19 -0
add-term-form.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php // adds a language select list in the Categories and Post tags admin panels ?>
2
+ <div class="form-field">
3
+ <label for="lang_choice"><?php _e('Language', 'polylang');?></label>
4
+ <select name="lang_choice" id="lang_choice">
5
+ <option value="-1"></option> <?php
6
+ foreach ($listlanguages as $language) {
7
+ printf("<option value='%s' %s>%s</option>\n", $language->term_id, $language == $lang ? 'selected="selected"' : '', $language->name);
8
+ } ?>
9
+ </select>
10
+ <p><?php _e('Sets the language', 'polylang');?></p>
11
+ </div>
admin.php ADDED
@@ -0,0 +1,450 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__).'/list-table.php');
4
+
5
+ class Polylang_Admin extends Polylang_Base {
6
+ function __construct() {
7
+ // adds a 'settings' link in the plugins table
8
+ $plugin_file = basename( dirname( __FILE__ ) ).'/polylang.php';
9
+ add_filter('plugin_action_links_'.$plugin_file, array(&$this, 'plugin_action_links'));
10
+
11
+ // adds the link to the languages panel in the wordpress admin menu
12
+ add_action('admin_menu', array(&$this, 'add_menus'));
13
+
14
+ // add the language column (as well as a filter by language) in 'All Posts' an 'All Pages' panels
15
+ add_filter('manage_posts_columns', array(&$this, 'add_post_column'), 10, 2);
16
+ add_filter('manage_pages_columns', array(&$this, 'add_post_column'));
17
+ add_action('manage_posts_custom_column', array(&$this, 'post_column'), 10, 2);
18
+ add_action('manage_pages_custom_column', array(&$this, 'post_column'), 10, 2);
19
+ add_filter('parse_query',array(&$this,'parse_query'));
20
+ add_action('restrict_manage_posts', array(&$this, 'restrict_manage_posts'));
21
+
22
+ // adds the Languages box in the 'Edit Post' and 'Edit Page' panels
23
+ add_action('add_meta_boxes', array(&$this, 'add_meta_boxes'));
24
+
25
+ // adds actions related to languages when saving aor deleting posts and pages
26
+ add_action('save_post', array(&$this, 'save_post'));
27
+ add_action('before_delete_post', array(&$this, 'delete_post'));
28
+
29
+ // adds the language field in the 'Categories' and 'Post Tags' panels
30
+ add_action('category_add_form_fields', array(&$this, 'add_term_form'));
31
+ add_action('post_tag_add_form_fields', array(&$this, 'add_term_form'));
32
+
33
+ // adds the language field and translations tables in the 'Edit Category' and 'Edit Tag' panels
34
+ add_action('category_edit_form_fields', array(&$this, 'edit_term_form'));
35
+ add_action('post_tag_edit_form_fields', array(&$this, 'edit_term_form'));
36
+
37
+ // adds the language column in the 'Categories' and 'Post Tags' tables
38
+ add_filter('manage_edit-category_columns', array(&$this, 'add_term_column'));
39
+ add_filter('manage_edit-post_tag_columns', array(&$this, 'add_term_column'));
40
+ add_action('manage_category_custom_column', array(&$this, 'term_column'), 10, 3);
41
+ add_action('manage_post_tag_custom_column', array(&$this, 'term_column'), 10, 3);
42
+
43
+ // adds actions related to languages when saving or deleting categories and post tags
44
+ add_action('created_category', array(&$this,'save_term'));
45
+ add_action('created_post_tag', array(&$this,'save_term'));
46
+ add_action('edited_category', array(&$this,'save_term'));
47
+ add_action('edited_post_tag', array(&$this,'save_term'));
48
+ add_action('delete_category', array(&$this,'delete_term'));
49
+ add_action('delete_post_tag', array(&$this,'delete_term'));
50
+
51
+ // refresh rewrite rules if the 'page_on_front' option is modified
52
+ add_action('update_option', array(&$this,'update_option'));
53
+ }
54
+
55
+ // adds a 'settings' link in the plugins table
56
+ function plugin_action_links($links) {
57
+ $settings_link = '<a href="admin.php?page=mlang">' . __('Settings') . '</a>';
58
+ array_unshift( $links, $settings_link );
59
+ return $links;
60
+ }
61
+
62
+ // adds the link to the languages panel in the wordpress admin menu
63
+ function add_menus() {
64
+ add_submenu_page('options-general.php', __('Languages','polylang'), __('Languages','polylang'), 'manage_options', 'mlang', array($this, 'languages_page'));
65
+ }
66
+
67
+ // the languages panel
68
+ function languages_page() {
69
+ global $wp_rewrite;
70
+ $options = get_option('polylang');
71
+
72
+ $listlanguages = $this->get_languages_list();
73
+ $list_table = new Polylang_List_Table();
74
+
75
+ $action = '';
76
+ if (isset($_REQUEST['action']))
77
+ $action = $_REQUEST['action'];
78
+
79
+ switch ($action) {
80
+ case 'add':
81
+ check_admin_referer( 'add-lang', '_wpnonce_add-lang' );
82
+
83
+ if (isset($_POST['name']) && isset($_POST['description'])) {
84
+ wp_insert_term($_POST['name'],'language',array('slug'=>$_POST['slug'], 'description'=>$_POST['description']));
85
+ $wp_rewrite->flush_rules(); // refresh rewrite rules
86
+ }
87
+ if (!isset($options['default_lang'])) { // if this is the first language created, set it as default language
88
+ $options['default_lang'] = $_POST['slug'];
89
+ update_option('polylang', $options);
90
+ }
91
+ wp_redirect('admin.php?page=mlang'); // to refresh the page (possible thanks to the $_GET['noheader']=true)
92
+ exit;
93
+ break;
94
+
95
+ case 'delete':
96
+ check_admin_referer( 'delete-lang');
97
+
98
+ if (isset($_GET['lang'])) {
99
+ $lang = $this->get_language($_GET['lang']);
100
+ $lang_slug = $lang->slug;
101
+
102
+ // delete all translations in posts in this language
103
+ $args = array('numberposts'=>-1, 'taxonomy' => 'language', 'term' => $lang_slug, 'post_type'=>'any', 'post_status'=>'any');
104
+ $posts = get_posts($args);
105
+ foreach ($posts as $post) {
106
+ foreach ($languages as $language) {
107
+ delete_post_meta($post->ID, '_lang-'.$language->slug);
108
+ }
109
+ }
110
+
111
+ // delete references to this language in all posts
112
+ $args = array('numberposts'=>-1, 'meta_key'=>'_lang-'.$lang_slug, 'post_type'=>'any', 'post_status'=>'any');
113
+ $posts = get_posts($args);
114
+ foreach ($posts as $post) {
115
+ delete_post_meta($post->ID, '_lang-'.$lang_slug);
116
+ }
117
+
118
+ // delete references to this language in categories & post tags
119
+ $terms = get_terms(array('category', 'post_tag'), 'get=all');
120
+ foreach ($terms as $term) {
121
+ if ($this->get_term_language($term->term_id) == $lang) {
122
+ foreach ($languages as $language) {
123
+ delete_metadata('term', $term->term_id, '_lang-'.$language->slug); // deletes translations of this term
124
+ }
125
+ delete_metadata('term', $term->term_id, '_language', $_GET['lang']); // delete language of this term
126
+ }
127
+ delete_metadata('term', $term->term_id, '_lang-'.$lang_slug); // deletes references to this term in translated term
128
+ }
129
+
130
+ // delete the language itself
131
+ wp_delete_term($_GET['lang'], 'language');
132
+ $wp_rewrite->flush_rules(); // refresh rewrite rules
133
+
134
+ // oops ! we deleted the default language...
135
+ if ($options['default_lang'] == $lang_slug) {
136
+ if (!empty($languages))
137
+ $options['default_lang'] = $languages[0]->slug; // arbitrary choice...
138
+ else
139
+ unset($options['default_lang']);
140
+ update_option('polylang', $options);
141
+ }
142
+ }
143
+ wp_redirect('admin.php?page=mlang'); // to refresh the page (possible thanks to the $_GET['noheader']=true)
144
+ exit;
145
+ break;
146
+
147
+ case 'edit':
148
+ if (isset($_GET['lang']))
149
+ $edit_lang = $this->get_language($_GET['lang']);
150
+ break;
151
+
152
+ case 'update':
153
+ check_admin_referer( 'add-lang', '_wpnonce_add-lang' );
154
+
155
+ if (isset($_POST['lang'])) {
156
+ // Update links to this language in posts and terms in case the slug has been modified
157
+ $lang = $this->get_language($_POST['lang']);
158
+ $old_slug = $lang->slug;
159
+
160
+ if ($old_slug != $_POST['slug']) {
161
+ // update the language slug in posts meta
162
+ $args = array('numberposts'=>-1, 'meta_key'=>'_lang-'.$old_slug, 'post_type'=>'any', 'post_status'=>'any');
163
+ $posts = get_posts($args);
164
+ foreach ($posts as $post) {
165
+ $post_id = get_post_meta($post->ID, '_lang-'.$old_slug, true);
166
+ delete_post_meta($post->ID, '_lang-'.$old_slug);
167
+ update_post_meta($post->ID, '_lang-'.$_POST['slug'], $post_id);
168
+ }
169
+
170
+ // update the language slug in categories & post tags meta
171
+ $terms = get_terms(array('category', 'post_tag'), 'get=all');
172
+ foreach ($terms as $term) {
173
+ $term_id = get_metadata('term', $term->term_id, '_lang-'.$old_slug, true);
174
+ if ($term_id) {
175
+ delete_metadata('term', $term->term_id, '_lang-'.$old_slug);
176
+ update_metadata('term', $term->term_id, '_lang-'.$_POST['slug'], $term_id);
177
+ }
178
+ }
179
+ }
180
+
181
+ // and finally update the language itself
182
+ wp_update_term($_POST['lang'], 'language', array('name'=>$_POST['name'], 'slug'=>$_POST['slug'], 'description'=>$_POST['description']));
183
+ $wp_rewrite->flush_rules(); // refresh rewrite rules
184
+ }
185
+ wp_redirect('admin.php?page=mlang'); // to refresh the page (possible thanks to the $_GET['noheader']=true)
186
+ exit;
187
+ break;
188
+
189
+ case 'options':
190
+ check_admin_referer( 'options-lang', '_wpnonce_options-lang' );
191
+
192
+ $options['rewrite'] = $_POST['rewrite'];
193
+ isset($_POST['browser']) ? $options['browser'] = 1 : $options['browser'] = 0;
194
+ $options['default_lang'] = $_POST['default_lang'];
195
+ update_option('polylang', $options);
196
+
197
+ // refresh refresh permalink structure and rewrite rules in case rewrite option has been modified
198
+ $wp_rewrite->extra_permastructs['language'][0] = $options['rewrite'] ? '%language%' : '/language/%language%';
199
+ $wp_rewrite->flush_rules();
200
+ break;
201
+
202
+ default:
203
+ }
204
+
205
+ // prepare the list table of languages
206
+ $data = array();
207
+ foreach ($listlanguages as $lang)
208
+ $data[] = (array) $lang;
209
+
210
+ $list_table->prepare_items($data);
211
+
212
+ // displays the page
213
+ include(dirname(__FILE__).'/languages-form.php');
214
+ }
215
+
216
+ // adds the language column (before the date column) in the posts and pages list table
217
+ function add_post_column($columns, $post_type ='') {
218
+ if (in_array($post_type, array('', 'post', 'page'))) {
219
+ $keys = array( 'date', 'comments' );
220
+ foreach ($keys as $k) {
221
+ if (array_key_exists($k, $columns))
222
+ $end[$k] = array_pop($columns);
223
+ }
224
+
225
+ $columns['language'] = __('Language', 'polylang');
226
+
227
+ if (isset($end))
228
+ $columns = array_merge($columns, $end);
229
+ }
230
+ return $columns;
231
+ }
232
+
233
+ // fills the language column in the posts table
234
+ function post_column($column, $post_id) {
235
+ $lang = $this->get_post_language($post_id);
236
+ if ($lang && $column == 'language')
237
+ echo $lang->name;
238
+ }
239
+
240
+ // converts language term_id to slug in $query
241
+ // needed to filter the posts by language with wp_dropdown_categories in restrict_manage_posts
242
+ function parse_query($query) {
243
+ global $pagenow;
244
+ $qvars = &$query->query_vars;
245
+ if ($pagenow=='edit.php' && isset($qvars['lang']) && is_numeric($qvars['lang'])) {
246
+ $lang = $this->get_language($qvars['lang']);
247
+ if ($lang)
248
+ $qvars['lang'] = $lang->slug;
249
+ }
250
+ }
251
+
252
+ // adds a filter for languages in the Posts and Pages panels
253
+ function restrict_manage_posts() {
254
+ global $typenow;
255
+ global $wp_query;
256
+ $languages = $this->get_languages_list();
257
+
258
+ if (!empty($languages) && in_array($typenow, array('', 'post', 'page'))) {
259
+ $qvars = $wp_query->query;
260
+ wp_dropdown_categories(array(
261
+ 'show_option_all' => __('Show all languages', 'polylang'),
262
+ 'name' => 'lang',
263
+ 'selected' => isset($qvars['lang']) ? $qvars['lang'] : 0,
264
+ 'taxonomy' => 'language'));
265
+ }
266
+ }
267
+
268
+ // adds the Languages box in the 'Edit Post' and 'Edit Page' panels
269
+ function add_meta_boxes() {
270
+ add_meta_box('ml_box', __('Languages','multiLang'), array(&$this,'post_language'), 'post', 'side','high');
271
+ add_meta_box('ml_box', __('Languages','multiLang'), array(&$this,'post_language'), 'page', 'side','high');
272
+ }
273
+
274
+ // the Languages metabox in the 'Edit Post' and 'Edit Page' panels
275
+ function post_language() {
276
+ global $post_ID;
277
+ $post_type = get_post_type($post_ID);
278
+
279
+ $lang = $this->get_post_language($post_ID);
280
+ if (isset($_GET['new_lang']))
281
+ $lang = $this->get_language($_GET['new_lang']);
282
+
283
+ include(dirname(__FILE__).'/post-metabox.php');
284
+ }
285
+
286
+ // called when a post (or page) is saved, published or updated
287
+ // the underscore in '_lang' hides the post meta in the Custom Fields metabox in the Edit Post screen
288
+ function save_post($post_id) {
289
+ $id = wp_is_post_revision($post_id);
290
+ if ($id)
291
+ $post_id = $id;
292
+
293
+ if (isset($_POST['lang_choice']))
294
+ wp_set_object_terms($post_id, $_POST['lang_choice'], 'language' );
295
+
296
+ $lang = $this->get_post_language($post_id);
297
+ $listlanguages = $this->get_languages_list();
298
+ foreach ($listlanguages as $language) {
299
+ if (isset($_POST[$language->slug])) {
300
+ $value = $_POST[$language->slug];
301
+ if ($value)
302
+ update_post_meta($post_id, '_lang-'.$language->slug, $value); // saves the links to translated posts
303
+ }
304
+ if ($lang && $language != $lang){
305
+ update_post_meta($this->get_translated_post($post_id, $language), '_lang-'.$lang->slug, $post_id); // tells the translated to link to this post
306
+ }
307
+ }
308
+
309
+ // propagates translations between them
310
+ foreach ($listlanguages as $language) {
311
+ foreach ($listlanguages as $lg) {
312
+ $id = $this->get_translated_post($post_id, $lg);
313
+ if ($lg != $lang && $lg != $language && $id)
314
+ update_post_meta($this->get_translated_post($post_id, $language), '_lang-'.$lg->slug, $id);
315
+ }
316
+ }
317
+ }
318
+
319
+ // called when a post (or page) is deleted
320
+ function delete_post($post_id) {
321
+ $id = wp_is_post_revision($post_id);
322
+ if ($id)
323
+ $post_id = $id;
324
+
325
+ $lang = $this->get_post_language($post_id);
326
+ if($lang) {
327
+ $listlanguages = $this->get_languages_list();
328
+ foreach ($listlanguages as $language) {
329
+ delete_post_meta($this->get_translated_post($post_id, $language), '_lang-'.$lang->slug); // delete links to this post
330
+ // WP deletes post metas linked to this post so it is useless to do it before
331
+ }
332
+ }
333
+ }
334
+
335
+ // adds the language field in the 'Categories' and 'Post Tags' panels
336
+ function add_term_form() {
337
+ $lang = NULL;
338
+ if (isset($_GET['new_lang']))
339
+ $lang = $this->get_language($_GET['new_lang']);
340
+
341
+ $listlanguages = $this->get_languages_list();
342
+
343
+ // displays the language field
344
+ include(dirname(__FILE__).'/add-term-form.php');
345
+ }
346
+
347
+ // adds the language field and translations tables in the 'Edit Category' and 'Edit Tag' panels
348
+ function edit_term_form($tag) {
349
+ $term_id = $tag->term_id;
350
+ $lang = $this->get_term_language($term_id);
351
+
352
+ $listlanguages = $this->get_languages_list();
353
+ $taxonomy = $tag->taxonomy;
354
+
355
+ include(dirname(__FILE__).'/edit-term-form.php');
356
+ }
357
+
358
+ // adds the language column (before the posts column) in the 'Categories' or Post Tags table
359
+ function add_term_column($columns) {
360
+ if (array_key_exists('posts', $columns))
361
+ $end = array_pop($columns);
362
+
363
+ $columns['language'] = __('Language', 'polylang');
364
+
365
+ if (isset($end))
366
+ $columns['posts'] = $end;
367
+
368
+ return $columns;
369
+ }
370
+
371
+ // fills the language column in the 'Categories' or Post Tags table
372
+ function term_column($empty, $column, $term_id) {
373
+ $lang = $this->get_term_language($term_id);
374
+ if ($lang && $column == 'language')
375
+ echo $lang->name;
376
+ }
377
+
378
+ // called when a category or post tag is created or edited
379
+ function save_term($term_id) {
380
+ if (isset($_POST['lang_choice']) && $_POST['lang_choice'] != -1 ) {
381
+ update_metadata('term', $term_id, '_language', $_POST['lang_choice'] );
382
+ $lang = $this->get_language($_POST['lang_choice']);
383
+
384
+ $listlanguages = $this->get_languages_list();
385
+ foreach ($listlanguages as $language) {
386
+ $slug = '_lang-'.$language->slug;
387
+ if (isset($_POST[$slug]) && $_POST[$slug] != -1) {
388
+ update_metadata('term', $term_id, $slug, $_POST[$slug] );
389
+ update_metadata('term', $_POST[$slug], '_lang-'.$lang->slug, $term_id );
390
+ }
391
+ }
392
+ }
393
+
394
+ $qvars = $this->get_referer_vars();
395
+ if (isset($qvars['from_tag']) && isset($qvars['from_lang']) && isset($qvars['new_lang'])) {
396
+ $from_lang = $this->get_language($qvars['from_lang']);
397
+ update_metadata('term', $term_id, '_lang-'.$from_lang->slug, $qvars['from_tag'] );
398
+ $new_lang = $this->get_language($qvars['new_lang']);
399
+ update_metadata('term', $qvars['from_tag'], '_lang-'.$new_lang->slug, $term_id );
400
+ }
401
+
402
+ // propagates translations between them
403
+ foreach ($listlanguages as $language) {
404
+ foreach ($listlanguages as $lg) {
405
+ $id = $this->get_translated_term($term_id, $lg);
406
+ if ($lg != $lang && $lg != $language && $id)
407
+ update_metadata('term',$this->get_translated_term($term_id, $language), '_lang-'.$lg->slug, $id);
408
+ }
409
+ }
410
+ }
411
+
412
+ // called when a category or post tag is deleted
413
+ function delete_term($term_id) {
414
+ $lang = $this->get_term_language($term_id);
415
+ if($lang) {
416
+ delete_metadata('term', $term_id, '_language' );
417
+ $listlanguages = $this->get_languages_list();
418
+ foreach ($listlanguages as $language) {
419
+ delete_metadata('term', $this->get_translated_term($term_id, $language), '_lang-'.$lang->slug); // delete links to this term
420
+ }
421
+ foreach ($listlanguages as $language) {
422
+ delete_metadata('term', $term_id, '_lang-'.$language->slug);
423
+ }
424
+ }
425
+ }
426
+
427
+ // returns all terms in the $taxonomy in the $term_language which have no translation in the $translation_language
428
+ function get_terms_not_translated($taxonomy, $term_language, $translation_language) {
429
+ $new_terms = array();
430
+ $terms = get_terms($taxonomy, 'hide_empty=0');
431
+ foreach ($terms as $term) {
432
+ $lang = $this->get_term_language($term->term_id);
433
+ if ($lang && $lang->name == $term_language->name) {
434
+ $translated_term = $this->get_translated_term($term->term_id, $translation_language);
435
+ if (!$translated_term)
436
+ $new_terms[] = $term;
437
+ }
438
+ }
439
+ return $new_terms;
440
+ }
441
+
442
+ // refresh rewrite rules if the 'page_on_front' option is modified
443
+ function update_option($option) {
444
+ global $wp_rewrite;
445
+ if ($option == 'page_on_front')
446
+ $wp_rewrite->flush_rules();
447
+ }
448
+ } // class Polylang_Admin
449
+
450
+ ?>
base.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Polylang_Base {
4
+
5
+ // returns the query variables of the referer
6
+ function get_referer_vars() {
7
+ $qvars = array();
8
+ $referer = wp_get_referer();
9
+ if ($referer) {
10
+ $urlparts = parse_url($referer);
11
+ if (isset($urlparts['query'])) {
12
+ parse_str($urlparts['query'], $qvars);
13
+ }
14
+ }
15
+ return $qvars;
16
+ }
17
+
18
+ // returns the list of available languages
19
+ function get_languages_list($hide_empty = false) {
20
+ return get_terms('language', array('hide_empty'=>$hide_empty));
21
+ }
22
+
23
+ // returns the language by its id or its slug
24
+ function get_language($value) {
25
+ if (is_numeric($value))
26
+ $field = 'id';
27
+ elseif (is_string($value))
28
+ $field = 'slug';
29
+
30
+ return get_term_by($field, $value , 'language');
31
+ }
32
+
33
+ // returns the language of a post
34
+ function get_post_language($post_id) {
35
+ $lang = get_the_terms($post_id, 'language' );
36
+ return ($lang) ? reset($lang) : NULL; // there's only one language per post : first element of the array returned
37
+ }
38
+
39
+ // returns the id of the translation of a post
40
+ function get_translated_post($post_id, $language) {
41
+ return get_post_meta($post_id, '_lang-'.$language->slug, true);
42
+ }
43
+
44
+ // among the post and its translations, returns the id of the post which is in $language
45
+ function get_post($post_id, $language) {
46
+ $lang = $this->get_post_language($post_id);
47
+ return $lang->slug == $language->slug ? $post_id : $this->get_translated_post($post_id, $language);
48
+ }
49
+
50
+ // returns the language of a term
51
+ function get_term_language($term_id) {
52
+ $value = get_metadata('term', $term_id, '_language', true);
53
+ return $this->get_language($value);
54
+ }
55
+
56
+ // returns the id of the translation of a term (category or post_tag)
57
+ function get_translated_term($term_id, $language) {
58
+ return get_metadata('term', $term_id, '_lang-'.$language->slug, true);
59
+ }
60
+
61
+ } //class Polylang_Base
62
+ ?>
edit-term-form.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // adds languages related fields in Edit Category and Edit Tag admin panels
3
+ // unfortunately can't reuse add-term-for.php as WordPress uses here a table instead of div :(
4
+
5
+ // displays the language select list
6
+ ?>
7
+ <tr class="form-field">
8
+ <th scope="row" valign="top"><label for="lang_choice"><?php _e('Language', 'polylang');?></label></th>
9
+ <td><select name="lang_choice" id="lang_choice">
10
+ <option value="-1"></option> <?php
11
+ foreach ($listlanguages as $language) {
12
+ printf("<option value='%s' %s>%s</option>\n", $language->term_id, $language == $lang ? 'selected="selected"' : '', $language->name);
13
+ } ?>
14
+ </select><br />
15
+ <span class="description"><?php _e('Sets the language', 'polylang');?></span></td>
16
+ </tr>
17
+
18
+ <?php
19
+ // displays the translations fields
20
+ // a table in the WP table is quite ugly but why WordPress does use a table instead of div as in the add term form ?
21
+ // FIXME inline CSS
22
+
23
+ if ($lang) { // do not display translation fields if term language is not set ?>
24
+ <tr class="form-field">
25
+ <th scope="row" valign="top"><?php _e('Translations', 'polylang');?></th>
26
+ <td><table>
27
+ <thead><tr>
28
+ <th style="padding: 0px; font-weight: bold"><?php _e('Language', 'polylang');?></th>
29
+ <th style="padding: 0px; font-weight: bold"><?php _e('Translation', 'polylang');?></th>
30
+ <th style="padding: 0px; font-weight: bold"><?php _e('Edit', 'polylang');?></th>
31
+ </tr></thead>
32
+ <tbody>
33
+ <?php foreach ($listlanguages as $language) {
34
+ if ($language != $lang) {
35
+ $value = $this->get_translated_term($term_id, $language);?>
36
+ <tr><td style="padding: 0px"><?php echo $language->name;?></td>
37
+ <?php if (!$value) {
38
+ $translations = $this->get_terms_not_translated($taxonomy, $language, $lang);
39
+ if (!empty($translations)) { ?>
40
+ <td style="padding: 0px">
41
+ <select name="_lang-<?php echo $language->slug;?>" id="_lang-<?php echo $language->slug;?>">
42
+ <option value="-1"></option> <?php
43
+ foreach ($translations as $translation) { ?>
44
+ <option value="<?php echo $translation->term_id;?>"><?php echo $translation->name;?></option> <?php
45
+ } ?>
46
+ </select>
47
+ </td> <?php
48
+ }
49
+ else { ?>
50
+ <td style="padding: 0px">
51
+ </td> <?php
52
+ } ?>
53
+ <td style="padding: 0px">
54
+ <?php printf('<a href="edit-tags.php?taxonomy=%s&amp;from_tag=%s&amp;from_lang=%s&amp;new_lang=%s">%s</a>',
55
+ $taxonomy, $term_id, $lang->slug, $language->slug, __('Add new','polylang')) ?>
56
+ </td> <?php
57
+ }
58
+ else { ?>
59
+ <td style="padding: 0px"><?php
60
+ $translation_id = $this->get_translated_term($term_id, $language);
61
+ $translation = get_term_by('id', $translation_id, $taxonomy);
62
+ echo $translation->name; ?>
63
+ </td>
64
+ <td style="padding: 0px">
65
+ <?php printf('<a href="edit-tags.php?action=edit&amp;taxonomy=%S&amp;tag_ID=%s">%s</a>', $taxonomy, $value, __('Edit','polylang')) ?>
66
+ </td> <?php
67
+ } ?>
68
+ </tr><?php
69
+ } // if (!$value)
70
+ } // foreach ?>
71
+ </tbody>
72
+ </table></td>
73
+ </tr> <?php
74
+ } // if ($lang) ?>
languages-form.php ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php // displays the Languages admin panel
2
+
3
+ // I don't use the custom taxonomy form provide by Wordpress because I want to modify the labels below the fields...
4
+ // There is currently (3.2) no filter to do this
5
+
6
+ // The term fields are used as follows :
7
+ // name -> language name (used only for display)
8
+ // slug -> language code (ideally 2-letters ISO 639-1 language code but I currently use it only as slug so it doesn't matter)
9
+ // description -> WordPress Locale for the language. Here if something wrong is used, the .mo files will not be loaded...
10
+
11
+ ?>
12
+ <div class="wrap">
13
+ <?php screen_icon('options-general'); ?>
14
+ <h2><?php _e('Languages','polylang') ?></h2>
15
+
16
+ <div id="col-container">
17
+ <div id="col-right">
18
+ <div class="col-wrap">
19
+
20
+ <?php $list_table->display(); // displays the language list in a table ?>
21
+
22
+ </div> <!-- col-wrap -->
23
+ </div> <!-- col-right -->
24
+
25
+ <div id="col-left">
26
+ <div class="col-wrap">
27
+
28
+ <div class="form-wrap">
29
+ <h3><?php echo $action=='edit' ? _e('Edit language','polylang') : _e('Add new language','polylang'); ?></h3>
30
+
31
+ <?php // displays the add (or edit) language form
32
+
33
+ // adds noheader=true in the action url to allow using wp_redirect when processing the form ?>
34
+ <form id="add-lang" method="post" action="admin.php?page=mlang&amp;noheader=true" class="validate">
35
+ <?php wp_nonce_field('add-lang', '_wpnonce_add-lang');
36
+
37
+ if ($action=='edit') {?>
38
+ <input type="hidden" name="action" value="update" />
39
+ <input type="hidden" name="lang" value="<?php echo $edit_lang->term_id;?>" /><?php
40
+ }
41
+ else { ?>
42
+ <input type="hidden" name="action" value="add" /><?php
43
+ }?>
44
+
45
+ <div class="form-field form-required">
46
+ <label for="name"><?php _e('Full name', 'polylang');?></label>
47
+ <input name="name" id="name" type="text" value="<?php if ($action=='edit') echo $edit_lang->name;?>" size="40" aria-required="true" />
48
+ <p><?php _e('The name is how it is displayed on your site (for example: English).', 'polylang');?></p>
49
+ </div>
50
+
51
+ <div class="form-field form-required">
52
+ <label for="description"><?php _e('Locale', 'polylang');?></label>
53
+ <input name="description" id="description" type="text" value="<?php if ($action=='edit') echo $edit_lang->description;?>" size="40" aria-required="true" />
54
+ <p><?php _e('Wordpress Locale for the language (for example: en_US). You will need to install the .mo file for this language.', 'polylang');?></p>
55
+ </div>
56
+
57
+ <div class="form-field">
58
+ <label for="slug"><?php _e('Language code', 'polylang');?></label>
59
+ <input name="slug" id="slug" type="text" value="<?php if ($action=='edit') echo $edit_lang->slug;?>" size="40" />
60
+ <p><?php _e('2-letters ISO 639-1 language code (for example: en)', 'polylang');?></p>
61
+ </div>
62
+
63
+ <?php if ($action=='edit')
64
+ submit_button(__('Update'), 'button'); // since WP 3.1
65
+ else
66
+ submit_button(__('Add new language', 'polylang'), 'button'); // since WP 3.1?>
67
+
68
+ </form>
69
+ </div> <!-- form-wrap -->
70
+ </div> <!-- col-wrap -->
71
+ </div> <!-- col-left -->
72
+ </div> <!-- col-container -->
73
+
74
+ <? // displays the Polylang options form
75
+ //FIXME one inline CSS ?>
76
+ <div class="form-wrap">
77
+ <h3><?php _e('Options','polylang');?></h3>
78
+
79
+ <form id="options-lang" method="post" action="admin.php?page=mlang" class="validate">
80
+ <?php wp_nonce_field('options-lang', '_wpnonce_options-lang');?>
81
+ <input type="hidden" name="action" value="options" />
82
+
83
+ <table class="form-table">
84
+
85
+ <tr>
86
+ <th style="width: 300px;"><label><?php printf ('<input name="rewrite" type="radio" value="0" %s /> %s',
87
+ $options['rewrite'] ? '' : 'checked="checked"', __('Keep /language/ in pretty permalinks', 'polylang')); ?></label></th>
88
+ <td><code><?php echo home_url('language/en/'); ?></code></td>
89
+ </tr>
90
+
91
+ <tr>
92
+ <th><label><?php printf ('<input name="rewrite" type="radio" value="1" %s /> %s',
93
+ $options['rewrite'] ? 'checked="checked"' : '', __('Remove /language/ in pretty permalinks', 'polylang')); ?></label></th>
94
+ <td><code><?php echo home_url('en/'); ?></code></td>
95
+ </tr>
96
+
97
+ <tr>
98
+ <th><?php _e('The front page default language is : ', 'polylang');?></th>
99
+ <td><label><?php printf('<input name="browser" type="checkbox" value="1" %s /> %s',
100
+ $options['browser'] ? 'checked="checked"' :'', __('set by the browser preference', 'polylang')) ?></label>
101
+ <label><?php _e('otherwise: ', 'polylang');?><select name="default_lang" id="default_lang">
102
+ <?php $listlanguages = $this->get_languages_list();
103
+ foreach ($listlanguages as $language) {
104
+ printf("<option value=%s %s >%s</option>\n", $language->slug, $options['default_lang'] == $language->slug ? 'selected="selected"' : '', $language->name);
105
+ } ?>
106
+ </select></label>
107
+ </td>
108
+ </tr>
109
+
110
+ </table>
111
+
112
+ <?php submit_button(); // since WP 3.1 ?>
113
+
114
+ </form>
115
+ </div> <!-- form-wrap -->
116
+
117
+ </div> <!-- wrap -->
list-table.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Thanks to Matt Van Andel (http://www.mattvanandel.com) for most of this code !
4
+
5
+ if(!class_exists('WP_List_Table')){
6
+ require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
7
+ }
8
+
9
+ class Polylang_List_Table extends WP_List_Table {
10
+ function __construct() {
11
+ parent::__construct( array(
12
+ 'singular' => __('Language','polylang'),
13
+ 'plural' => __('Languages','polylang'),
14
+ 'ajax'=> false)
15
+ );
16
+ }
17
+
18
+ function column_default( $item, $column_name){
19
+ switch($column_name){
20
+ case 'description':
21
+ case 'slug':
22
+ case 'count':
23
+ return $item[$column_name];
24
+ default:
25
+ }
26
+ }
27
+
28
+ function column_name($item){
29
+ $actions = array(
30
+ 'edit' => sprintf('<a href="?page=mlang&amp;action=edit&amp;lang=%s">%s</a>',$item['term_id'],__('Edit','polylang')),
31
+ 'delete' => '<a href="' . wp_nonce_url('?page=mlang&amp;action=delete&amp;noheader=true&amp;lang=' . $item['term_id'], 'delete-lang') .'">' . __('Delete','polylang') .'</a>'
32
+ );
33
+
34
+ return $item['name'].$this->row_actions($actions);
35
+ }
36
+
37
+ function column_cb($item){
38
+ return sprintf(
39
+ '<input type="checkbox" name="%1$s[]" value="%2$s" />',
40
+ /*$1%s*/ $this->_args['singular'],
41
+ /*$2%s*/ $item['term_id']
42
+ );
43
+ }
44
+
45
+ function get_columns(){
46
+ $columns = array(
47
+ 'cb' => '<input type="checkbox" />', //Render a checkbox instead of text
48
+ 'name' => __('Full name', 'polylang'),
49
+ 'description' => __('Locale', 'polylang'),
50
+ 'slug' => __('Code', 'polylang'),
51
+ 'count' => __('Posts', 'polylang')
52
+ );
53
+ return $columns;
54
+ }
55
+
56
+ function get_sortable_columns() {
57
+ $sortable_columns = array(
58
+ 'name' => array('name',true), // sorted by name by default
59
+ 'description' => array('description',false),
60
+ 'slug' => array('slug',false),
61
+ 'count' => array('count',false)
62
+ );
63
+ return $sortable_columns;
64
+ }
65
+
66
+ /*
67
+ function get_bulk_actions() {
68
+ return array('delete' => 'Delete');
69
+ }
70
+ */
71
+
72
+ function prepare_items($data = array()) {
73
+ $per_page = 5; // 5 languages per page
74
+ $columns = $this->get_columns();
75
+ $hidden = array();
76
+ $sortable = $this->get_sortable_columns();
77
+
78
+ $this->_column_headers = array($columns, $hidden, $sortable);
79
+
80
+ function usort_reorder($a,$b){
81
+ $orderby = (!empty($_REQUEST['orderby'])) ? $_REQUEST['orderby'] : 'name'; //If no sort, default to title
82
+ $order = (!empty($_REQUEST['order'])) ? $_REQUEST['order'] : 'asc'; //If no order, default to asc
83
+ $result = strcmp($a[$orderby], $b[$orderby]); //Determine sort order
84
+ return ($order==='asc') ? $result : -$result; //Send final sort direction to usort
85
+ }
86
+ usort($data, 'usort_reorder');
87
+
88
+ $current_page = $this->get_pagenum();
89
+ $total_items = count($data);
90
+ $data = array_slice($data,(($current_page-1)*$per_page),$per_page);
91
+ $this->items = $data;
92
+
93
+ $this->set_pagination_args( array(
94
+ 'total_items' => $total_items, //WE have to calculate the total number of items
95
+ 'per_page' => $per_page, //WE have to determine how many items to show on a page
96
+ 'total_pages' => ceil($total_items/$per_page) //WE have to calculate the total number of pages
97
+ ) );
98
+ }
99
+ }
100
+ ?>
polylang-fr_FR.mo ADDED
Binary file
polylang-fr_FR.po ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: polylang\n"
4
+ "Report-Msgid-Bugs-To: \n"
5
+ "POT-Creation-Date: 2011-09-20 17:23+0100\n"
6
+ "PO-Revision-Date: \n"
7
+ "Last-Translator: F. Demarle\n"
8
+ "Language-Team: \n"
9
+ "Language: \n"
10
+ "MIME-Version: 1.0\n"
11
+ "Content-Type: text/plain; charset=UTF-8\n"
12
+ "Content-Transfer-Encoding: 8bit\n"
13
+ "Plural-Forms: nplurals=2: nplural=n>1\n"
14
+ "X-Poedit-SourceCharset: utf-8\n"
15
+ "X-Poedit-KeywordsList: _e;__;_c\n"
16
+ "X-Poedit-Basepath: .\n"
17
+ "X-Poedit-SearchPath-0: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang\n"
18
+
19
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/edit-term-form.php:3
20
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/edit-term-form.php:20
21
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/admin.php:211
22
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/admin.php:346
23
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/post-metabox.php:19
24
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/add-term-form.php:2
25
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/list-table.php:12
26
+ msgid "Language"
27
+ msgstr "Langue"
28
+
29
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/edit-term-form.php:10
30
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/add-term-form.php:9
31
+ msgid "Sets the language"
32
+ msgstr "Définit la langue"
33
+
34
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/edit-term-form.php:17
35
+ msgid "Translations"
36
+ msgstr "Traductions"
37
+
38
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/edit-term-form.php:21
39
+ msgid "Translation"
40
+ msgstr "Traduction"
41
+
42
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/edit-term-form.php:22
43
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/edit-term-form.php:67
44
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/post-metabox.php:21
45
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/post-metabox.php:51
46
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/list-table.php:30
47
+ msgid "Edit"
48
+ msgstr "Modifier"
49
+
50
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/edit-term-form.php:52
51
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/post-metabox.php:42
52
+ msgid "Add new"
53
+ msgstr "Ajouter"
54
+
55
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/widget.php:5
56
+ msgid "Displays a language switcher"
57
+ msgstr "Affiche la liste des langues "
58
+
59
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/widget.php:6
60
+ msgid "Language Switcher"
61
+ msgstr "Liste des langues"
62
+
63
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/admin.php:57
64
+ msgid "Settings"
65
+ msgstr "Réglages"
66
+
67
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/admin.php:64
68
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/admin.php:253
69
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/admin.php:254
70
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/list-table.php:13
71
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/languages-form.php:3
72
+ msgid "Languages"
73
+ msgstr "Langues"
74
+
75
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/admin.php:244
76
+ msgid "Show all languages"
77
+ msgstr "Afficher toutes les langues"
78
+
79
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/post-metabox.php:3
80
+ msgid "Page's language:"
81
+ msgstr "Langue de la page"
82
+
83
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/post-metabox.php:5
84
+ msgid "Post's language:"
85
+ msgstr "Langue de l'article"
86
+
87
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/post-metabox.php:16
88
+ msgid "ID of posts in other languages:"
89
+ msgstr "ID des articles dans les autres langues"
90
+
91
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/post-metabox.php:20
92
+ msgid "Post ID"
93
+ msgstr "ID de l'article"
94
+
95
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/list-table.php:31
96
+ msgid "Delete"
97
+ msgstr "Supprimer"
98
+
99
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/list-table.php:48
100
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/languages-form.php:34
101
+ msgid "Full name"
102
+ msgstr "Nom"
103
+
104
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/list-table.php:49
105
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/languages-form.php:40
106
+ msgid "Locale"
107
+ msgstr ""
108
+
109
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/list-table.php:50
110
+ msgid "Code"
111
+ msgstr "Code"
112
+
113
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/list-table.php:51
114
+ msgid "Posts"
115
+ msgstr "Articles"
116
+
117
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/languages-form.php:19
118
+ msgid "Edit language"
119
+ msgstr "Modifier la langue"
120
+
121
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/languages-form.php:21
122
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/languages-form.php:54
123
+ msgid "Add new language"
124
+ msgstr "Ajouter une nouvelle langue"
125
+
126
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/languages-form.php:36
127
+ msgid "The name is how it is displayed on your site (for example: English)."
128
+ msgstr "Le nom est utilisé un peu partout sur le site (par exemple : Français)"
129
+
130
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/languages-form.php:42
131
+ msgid "Wordpress Locale for the language (for example: en_US). You will need to install the .mo file for this language."
132
+ msgstr "Code Wordpress pour la langue (par exemple : fr_FR). Vous aurez besoin d'installer les fichiers .mo correspondant"
133
+
134
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/languages-form.php:46
135
+ msgid "Language code"
136
+ msgstr "Code de la langue"
137
+
138
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/languages-form.php:48
139
+ msgid "2-letters ISO 639-1 language code (for example: en)"
140
+ msgstr "Code ISO 639-1 à 2 lettres (par exemple : fr)"
141
+
142
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/languages-form.php:52
143
+ msgid "Update"
144
+ msgstr "Mettre à jour"
145
+
146
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/languages-form.php:63
147
+ msgid "Options"
148
+ msgstr "Options"
149
+
150
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/languages-form.php:72
151
+ msgid "Keep /language/ in pretty permalinks"
152
+ msgstr "Conserve /language/ dans les permaliens"
153
+
154
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/languages-form.php:77
155
+ msgid "Remove /language/ in pretty permalinks"
156
+ msgstr "Supprime /language/ dans les permaliens"
157
+
158
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/languages-form.php:81
159
+ msgid "The front page default language is : "
160
+ msgstr "La langue par défaut de la page d'accueil est :"
161
+
162
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/languages-form.php:83
163
+ msgid "set by the browser preference"
164
+ msgstr "définie par les préférences du navigateur"
165
+
166
+ #: /home/fred/Documents/Web/test-flabellina.com/wordpress/wp-content/plugins/polylang/languages-form.php:84
167
+ msgid "otherwise: "
168
+ msgstr "sinon :"
169
+
170
+ #~ msgid "Title:"
171
+ #~ msgstr "Titre :"
172
+
polylang.php ADDED
@@ -0,0 +1,654 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Polylang
4
+ Plugin URI: http://wordpress.org/extend/plugins/polylang/
5
+ Version: 0.1
6
+ Author: F. Demarle
7
+ Description: Adds multilingual capability to Wordpress
8
+ */
9
+
10
+ /* Copyright 2011 F. Demarle
11
+
12
+ This program is free software; you can redistribute it and/or modify
13
+ it under the terms of the GNU General Public License, version 2, as
14
+ published by the Free Software Foundation.
15
+
16
+ This program is distributed in the hope that it will be useful,
17
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ GNU General Public License for more details.
20
+
21
+ You should have received a copy of the GNU General Public License
22
+ along with this program; if not, write to the Free Software
23
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
+ */
25
+
26
+ define('MULTILANG_VERSION', '0.1');
27
+ require_once(dirname(__FILE__).'/base.php');
28
+ require_once(dirname(__FILE__).'/admin.php');
29
+ require_once(dirname(__FILE__).'/widget.php');
30
+
31
+ class Polylang extends Polylang_Base {
32
+ var $curlang;
33
+ var $list_textdomains = array();
34
+ var $search_form_filter = false;
35
+
36
+ function __construct() {
37
+
38
+ // manages plugin activation and deactivation
39
+ register_activation_hook( __FILE__, array(&$this, 'activate') );
40
+ register_deactivation_hook( __FILE__, array(&$this, 'deactivate') );
41
+
42
+ // plugin and widget initialization
43
+ add_action('init', array(&$this,'init'));
44
+ add_action('widgets_init', array(&$this,'widgets_init'));
45
+
46
+ // rewrite rules
47
+ add_filter('rewrite_rules_array', array(&$this,'rewrite_rules_array' ));
48
+
49
+ // filters categories and post tags by language
50
+ add_filter('get_terms', array(&$this,'get_terms'), 10, 3);
51
+
52
+ if (is_admin())
53
+ new Polylang_Admin();
54
+ else {
55
+ // text domain management
56
+ add_filter('locale', array(&$this,'get_locale'));
57
+ add_filter('override_load_textdomain', array(&$this,'mofile'), 10, 3);
58
+ add_action('wp', array(&$this,'load_textdomains'));
59
+
60
+ // filters posts according to the language
61
+ add_filter('pre_get_posts', array(&$this,'pre_get_posts'));
62
+
63
+ // meta in the html head section
64
+ remove_action('wp_head', 'rel_canonical');
65
+ add_action('wp_head', array(&$this,'wp_head'));
66
+
67
+ // prevents redirection of the homepage
68
+ add_filter('redirect_canonical', array(&$this,'redirect_canonical'), 10, 2);
69
+
70
+ // adds javascript at the end of the document
71
+ add_action('wp_print_footer_scripts', array(&$this,'wp_print_footer_scripts'));
72
+
73
+ // adds the language information in the search form
74
+ add_filter('get_search_form', array(&$this,'get_search_form'));
75
+
76
+ // filters the pages according to the current language
77
+ add_filter('get_pages', array(&$this,'get_pages'), 10, 2);
78
+
79
+ // rewrites feed links to filter them by language
80
+ add_filter('feed_link', array(&$this,'feed_link'), 10, 2);
81
+
82
+ // rewrites archives links to filter them by language
83
+ add_filter('getarchives_join', array(&$this,'posts_join'));
84
+ add_filter('getarchives_where', array(&$this,'posts_where'));
85
+ add_filter('get_archives_link', array(&$this,'get_archives_link'));
86
+
87
+ // rewrites next and previous post links to filter them by language
88
+ add_filter('get_previous_post_join', array(&$this,'posts_join'));
89
+ add_filter('get_next_post_join', array(&$this,'posts_join'));
90
+ add_filter('get_previous_post_where', array(&$this,'posts_where'));
91
+ add_filter('get_next_post_where', array(&$this,'posts_where'));
92
+
93
+ // allows a new value for the 'show' parameter to display the homepage url according to the current language
94
+ add_filter('bloginfo_url', array(&$this,'bloginfo_url'), 10, 2);
95
+
96
+ // Template tags
97
+ add_action('the_languages', array(&$this,'the_languages'));
98
+ }
99
+ }
100
+
101
+ // plugin activation
102
+ function activate() {
103
+ // create the termmeta table - not provided by WP by default - if it does not already exists
104
+ // uses exactly the same model as other meta tables to be able to use access functions provided by WP
105
+ global $wpdb;
106
+ $charset_collate = '';
107
+ if ( ! empty($wpdb->charset) )
108
+ $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
109
+ if ( ! empty($wpdb->collate) )
110
+ $charset_collate .= " COLLATE $wpdb->collate";
111
+
112
+ $table = $wpdb->prefix . 'termmeta';
113
+
114
+ $tables = $wpdb->get_results("show tables like '$table'");
115
+ if (!count($tables))
116
+ $wpdb->query("CREATE TABLE $table (
117
+ meta_id bigint(20) unsigned NOT NULL auto_increment,
118
+ term_id bigint(20) unsigned NOT NULL default '0',
119
+ meta_key varchar(255) default NULL,
120
+ meta_value longtext,
121
+ PRIMARY KEY (meta_id),
122
+ KEY term_id (term_id),
123
+ KEY meta_key (meta_key)
124
+ ) $charset_collate;");
125
+
126
+ // codex tells to use the init action to call register_taxonomy but I need it now for my rewrite rules
127
+ register_taxonomy('language', 'post', array('label' => false, 'query_var'=>'lang'));
128
+
129
+ // defines default values for options in case this is the first installation
130
+ $options = get_option('polylang');
131
+ if (!$options) {
132
+ $options['browser'] = 1; // default language for the front page is set by browser preference
133
+ $options['rewrite'] = 0; // do not remove /language/ in permalinks
134
+ }
135
+ $options['version'] = MULTILANG_VERSION; // do not manage versions yet but prepare for it
136
+ update_option('polylang', $options);
137
+
138
+ // add our rewrite rules
139
+ global $wp_rewrite;
140
+ $wp_rewrite->flush_rules();
141
+ }
142
+
143
+ // plugin deactivation
144
+ function deactivate() {
145
+ // delete our rewrite rules
146
+ remove_filter('rewrite_rules_array', array(&$this,'rewrite_rules_array' ));
147
+ global $wp_rewrite;
148
+ $wp_rewrite->flush_rules();
149
+ }
150
+
151
+ // some initialization
152
+ function init() {
153
+ global $wpdb;
154
+ $wpdb->termmeta = $wpdb->prefix . 'termmeta'; // registers the termmeta table in wpdb
155
+
156
+ // registers the language taxonomy
157
+ // codex: use the init action to call this function
158
+ register_taxonomy('language', 'post', array(
159
+ 'label' => false,
160
+ 'query_var'=>'lang',
161
+ 'update_count_callback' => '_update_post_term_count'));
162
+
163
+ // optionaly removes 'language' in permalinks so that we get http://www.myblog/en/ instead of http://www.myblog/language/en/
164
+ // the simple line of code is inspired by the WP No Category Base plugin : http://wordpresssupplies.com/wordpress-plugins/no-category-base/
165
+ $options = get_option('polylang');
166
+ if ($options['rewrite']) {
167
+ global $wp_rewrite;
168
+ $wp_rewrite->extra_permastructs['language'][0] = '%language%';
169
+ }
170
+
171
+ load_plugin_textdomain('polylang', false, dirname(plugin_basename( __FILE__ ))); // plugin i18n
172
+ }
173
+
174
+ // registers our widget
175
+ function widgets_init() {
176
+ register_widget('Polylang_Widget');
177
+ }
178
+
179
+ // rewrites rules if pretty permalinks are used
180
+ function rewrite_rules_array($rules) {
181
+ $options = get_option('polylang');
182
+ $newrules = array();
183
+ $listlanguages = $this->get_languages_list();
184
+
185
+ // modifies the rules created by WordPress when '/language/' is removed in permalinks
186
+ if ($options['rewrite']) {
187
+ foreach ($listlanguages as $language) {
188
+ $newrules[$language->slug.'/feed/(feed|rdf|rss|rss2|atom)/?$'] = 'index.php?lang='.$language->slug.'&feed=$matches[1]';
189
+ $newrules[$language->slug.'/(feed|rdf|rss|rss2|atom)/?$'] = 'index.php?lang='.$language->slug.'&feed=$matches[1]';
190
+ $newrules[$language->slug.'/page/?([0-9]{1,})/?$'] = 'index.php?lang='.$language->slug.'&paged=$matches[1]';
191
+ $newrules[$language->slug.'/?$'] = 'index.php?lang='.$language->slug;
192
+ }
193
+ unset($rules['([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$']); // => index.php?lang=$matches[1]&feed=$matches[2]
194
+ unset($rules['([^/]+)/(feed|rdf|rss|rss2|atom)/?$']); // => index.php?lang=$matches[1]&feed=$matches[2]
195
+ unset($rules['([^/]+)/page/?([0-9]{1,})/?$']); // => index.php?lang=$matches[1]&paged=$matches[2]
196
+ unset($rules['([^/]+)/?$']); // => index.php?lang=$matches[1]
197
+ }
198
+
199
+ $options['rewrite'] ? $base = '' : $base = 'language/';
200
+
201
+ // rewrite rules for comments feed filtered by language
202
+ foreach ($listlanguages as $language) {
203
+ $newrules[$base.$language->slug.'/comments/feed/(feed|rdf|rss|rss2|atom)/?$'] = 'index.php?lang='.$language->slug.'&feed=$matches[1]&withcomments=1';
204
+ $newrules[$base.$language->slug.'/comments/(feed|rdf|rss|rss2|atom)/?$'] = 'index.php?lang='.$language->slug.'&feed=$matches[1]&withcomments=1';
205
+ }
206
+ unset($rules['comments/feed/(feed|rdf|rss|rss2|atom)/?$']); // => index.php?&feed=$matches[1]&withcomments=1
207
+ unset($rules['comments/(feed|rdf|rss|rss2|atom)/?$']); // => index.php?&feed=$matches[1]&withcomments=1
208
+
209
+ // rewrite rules for archives filtered by language
210
+ foreach ($rules as $key => $rule) {
211
+ $is_archive = strpos($rule, 'year=') && !(
212
+ strpos($rule, 'p=') ||
213
+ strpos($rule, 'name=') ||
214
+ strpos($rule, 'page=') ||
215
+ strpos($rule, 'cpage=') );
216
+
217
+ if ($is_archive) {
218
+ foreach ($listlanguages as $language)
219
+ $newrules[$base.$language->slug.'/'.$key] = str_replace('?', '?lang='.$language->slug.'&', $rule);
220
+
221
+ unset($rules[$key]); // now useless
222
+ }
223
+ }
224
+
225
+ return $newrules + $rules;
226
+ }
227
+
228
+ // filters categories and post tags by language when needed (both in admin panels and frontend
229
+ function get_terms($terms, $taxonomies, $args) {
230
+ if (is_admin()) {
231
+ $screen = get_current_screen();
232
+ if (isset($screen))
233
+ // does nothing in the Categories, Post tags, Languages an Posts* admin panels
234
+ if ($screen->base == 'edit-tags' || $screen->base == 'toplevel_page_mlang' || $screen->base == 'edit')
235
+ return $terms;
236
+
237
+ // *FIXME I want all categories in the dropdown list and only the ones in the right language in the inline edit
238
+ // It seems that I need javascript to get the post_id as inline edit data are manipulated in inline-edit-post.js
239
+ }
240
+
241
+ // does nothing except on categories and post tags
242
+ if ( !in_array('category', $taxonomies) && !in_array('post_tag', $taxonomies) )
243
+ return $terms;
244
+
245
+ $lang = $this->get_current_language();
246
+ if ($lang) {
247
+ $slug = $lang->slug;
248
+ foreach($terms as $key => $term) {
249
+ $lang = $this->get_term_language($term->term_id);
250
+ if (!$lang || ($lang->slug) != $slug)
251
+ unset($terms[$key]); // remove terms with no language set or different language
252
+ }
253
+ }
254
+ return $terms;
255
+ }
256
+
257
+ // returns the language according to browser preference or the default language
258
+ function get_preferred_language() {
259
+ // check first is the user was already browsing this site
260
+ if ($lang = $this->get_language($_COOKIE['wordpress_polylang']))
261
+ return $lang;
262
+
263
+ // sets the browsing language according to the browser preferences
264
+ // code adapted from http://www.thefutureoftheweb.com/blog/use-accept-language-header
265
+ $options = get_option('polylang');
266
+ if ($options['browser']) {
267
+ $accept_langs = array();
268
+
269
+ if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
270
+ // break up string into pieces (languages and q factors)
271
+ preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $lang_parse);
272
+
273
+ if (count($lang_parse[1])) {
274
+ $accept_langs = array_combine($lang_parse[1], $lang_parse[4]); // create a list like "en" => 0.8
275
+ // set default to 1 for any without q factor
276
+ foreach ($accept_langs as $accept_lang => $val) {
277
+ if ($val === '') $accept_langs[$accept_lang] = 1;
278
+ }
279
+ arsort($accept_langs, SORT_NUMERIC); // sort list based on value
280
+ }
281
+ }
282
+
283
+ // looks through sorted list and use first one that matches our language list
284
+ $listlanguages = $this->get_languages_list(true); // hides languages with no post
285
+ foreach ($accept_langs as $accept_lang => $val) {
286
+ foreach ($listlanguages as $language) {
287
+ if (strpos($accept_lang, $language->slug) === 0 && !isset($pref_lang)) {
288
+ $pref_lang = $this->get_language($language->slug);
289
+ }
290
+ }
291
+ }
292
+ } // options['browser']
293
+
294
+ // either there is no preference in the browser or preferences does not match our language list or it is requested not to use the browser preference
295
+ if (!isset($pref_lang))
296
+ $pref_lang = $this->get_language($options['default_lang']);
297
+
298
+ return $pref_lang;
299
+ }
300
+
301
+ // returns the current language
302
+ function get_current_language() {
303
+ global $post_ID;
304
+
305
+ if($this->curlang)
306
+ return $this->curlang;
307
+
308
+ if (is_404())
309
+ return $this->get_preferred_language();
310
+
311
+ if (is_admin()) {
312
+ if (isset($post_ID))
313
+ $lang = $this->get_post_language($post_ID);
314
+
315
+ // trick to get the post number in the Post Tags metabox in the Edit Post screen (as $post_ID not defined)
316
+ $qvars = $this->get_referer_vars();
317
+ if (isset($qvars['post']))
318
+ $lang = $this->get_post_language($qvars['post']);
319
+ }
320
+ else {
321
+ $var = get_query_var('lang');
322
+ if ($var)
323
+ $lang = $this->get_language($var);
324
+ else {
325
+ $var = get_queried_object_id();
326
+ if ($var && is_single() || is_page())
327
+ $lang = $this->get_post_language($var);
328
+ else {
329
+ $var = get_query_var('cat');
330
+ if ($var)
331
+ $lang = $this->get_term_language($var);
332
+ else {
333
+ $var = get_query_var('tag_id');
334
+ if ($var)
335
+ $lang = $this->get_term_language($var);
336
+ }
337
+ }
338
+ }
339
+ }
340
+
341
+ return (isset($lang)) ? $lang : NULL;
342
+ }
343
+
344
+ // returns the locale based on current language
345
+ function get_locale($locale) {
346
+ if ($this->curlang)
347
+ $locale = $this->curlang->description;
348
+ return $locale;
349
+ }
350
+
351
+ // saves all text domains in a table for later usage
352
+ function mofile( $bool, $domain, $mofile) {
353
+ $this->list_textdomains[] = array ('mo' => $mofile, 'domain' => $domain);
354
+ return true; // prevents WP loading text domains as we will load them all later
355
+ }
356
+
357
+ // NOTE : I believe there are two ways for a plugin to force the WP language
358
+ // as done by xili_language and here : load text domains and reinitialize wp_locale with the action 'wp'
359
+ // as done by qtranslate : define the locale with the action 'plugins_loaded', but in this case, the language must be specified in the url.
360
+ function load_textdomains() {
361
+ // sets the current language and set a cookie to remember it
362
+ if ($this->curlang = $this->get_current_language())
363
+ setcookie('wordpress_polylang', $this->curlang->slug, time() + 31536000 /* 1 year */, COOKIEPATH, COOKIE_DOMAIN);
364
+
365
+ // our override_load_textdomain has done its job. let's remove it before calling load_textdomain
366
+ remove_filter('override_load_textdomain', array(&$this,'mofile'));
367
+
368
+ // now we can load text domains with the right language
369
+ foreach ($this->list_textdomains as $textdomain) {
370
+ $mo = preg_replace('#(.+)\/[a-zA-Z_]+\.mo$#', '$1/'.get_locale().'.mo', $textdomain['mo']); // replace the .mo file
371
+ load_textdomain( $textdomain['domain'], $mo);
372
+ }
373
+
374
+ global $wp_locale;
375
+ $wp_locale->init(); // reinitializes wp_locale for weekdays and months
376
+ }
377
+
378
+ // filters posts according to the language
379
+ function pre_get_posts($query) {
380
+
381
+ if (empty($query->query)) {
382
+
383
+ // sets the language according to browser preference or default language
384
+ $this->curlang = $this->get_preferred_language();
385
+
386
+ // redirect to the right translated page in case a static page is used as front page
387
+ $post_id = get_option('page_on_front');
388
+ if (isset($this->curlang) && $post_id) {
389
+ // a static page is used as front page
390
+ $language = $this->get_post_language($post_id);
391
+ if ($language->slug != $this->curlang->slug) {
392
+ // but the one defined in the "Reading Settings" panel is not in the right language, so let's redirect to the right one
393
+ $link_id = $this->get_translated_post($post_id, $this->curlang);
394
+ if ($link_id) {
395
+ $url = _get_page_link($link_id);
396
+ wp_redirect($url);
397
+ exit;
398
+ }
399
+ }
400
+ }
401
+ }
402
+
403
+ // filters recent posts to the current language
404
+ if ($query->is_home && $this->curlang)
405
+ $query->set('lang', $this->curlang->slug);
406
+
407
+ // remove pages from archives when the language is set
408
+ $qvars = $query->query_vars;
409
+ if (isset($qvars['m']) && isset($qvars['lang']))
410
+ $query->set('post_type', 'post');
411
+ }
412
+
413
+ function wp_head() {
414
+ // modifies the canonical link to the homepage
415
+ if (is_singular()) {
416
+ global $wp_the_query;
417
+
418
+ if ($id = $wp_the_query->get_queried_object_id()) {
419
+ if (is_page())
420
+ $link = _get_page_link($id); // ignores page_on_front unlike get_permalink
421
+ else
422
+ $link = get_permalink ($id);
423
+ echo "<link rel='canonical' href='$link' />\n";
424
+ }
425
+ }
426
+
427
+ // outputs references to translated pages (if exists) in the html head section
428
+ $listlanguages = $this->get_languages_list();
429
+ foreach ($listlanguages as $language) {
430
+ if ($language->slug != $this->curlang->slug) {
431
+ $url = $this->get_translation_url($language);
432
+ if ($url)
433
+ echo "<link hreflang='$language->slug' href='$url' rel='alternate' />\n";
434
+ }
435
+ }
436
+ }
437
+
438
+ // prevents redirection of the homepage
439
+ function redirect_canonical($redirect_url, $requested_url) {
440
+ if($requested_url == _get_page_link(get_option('page_on_front')))
441
+ return false;
442
+ return $redirect_url;
443
+ }
444
+
445
+ // adds some javascript workaround knowing it's not perfect...
446
+ function wp_print_footer_scripts() {
447
+ if ($this->curlang) {
448
+ $js = "<script type='text/javascript'>";
449
+
450
+ // modifies links to the homepage to filter by the right language
451
+ // since filtering home_url breaks things in the core and filtering bloginfo_url is not enough if the template uses home_url()
452
+ $url = rtrim(home_url(), '/');
453
+
454
+ if ($page = get_option('page_on_front'))
455
+ $newurl = _get_page_link($this->get_post($page, $this->curlang));
456
+ else
457
+ $newurl = get_term_link($this->curlang->slug, 'language');
458
+
459
+ $js .= "var e = document.getElementsByTagName('a');
460
+ for (var i = 0; i < e.length; i++) {
461
+ var href = e[i].href;
462
+ if (href == '$url' || href == '$url/') {
463
+ e[i].href = '$newurl';
464
+ }
465
+ }";
466
+
467
+ // modifies the search form since filtering get_search_form won't work if the template uses searchform.php
468
+ // don't use directly e[0] just in case there is somewhere else an element named 's'
469
+ // check before if the hidden input has not already been introduced by get_search_form
470
+ if (!$this->search_form_filter) {
471
+ $lang = $this->curlang->slug;
472
+ $js .= "e = document.getElementsByName('s');
473
+ for (i = 0; i < e.length; i++) {
474
+ if (e[i] == '[object HTMLInputElement]') {
475
+ var ih = document.createElement('input');
476
+ ih.type = 'hidden';
477
+ ih.name = 'lang';
478
+ ih.value = '$lang';
479
+ e[i].parentNode.appendChild(ih);
480
+ }
481
+ }";
482
+ }
483
+
484
+ $js .= "</script>";
485
+ echo $js;
486
+ }
487
+ }
488
+
489
+ // adds the language information in the search form
490
+ // FIXME does not work if searchform.php is used
491
+ function get_search_form($form) {
492
+ if ($form) {
493
+ $this->search_form_filter = true;
494
+ $form = str_replace('</form>', '<input type="hidden" name="lang" value="'.$this->curlang->slug.'" /></form>', $form);
495
+ }
496
+ return $form;
497
+ }
498
+
499
+ // filters the pages according to the current language
500
+ function get_pages($pages, $r) {
501
+ if (isset($this->curlang)) {
502
+ foreach ($pages as $key => $page) {
503
+ $lang = $this->get_post_language($page->ID);
504
+ if ($this->curlang != $lang)
505
+ unset($pages[$key]);
506
+ }
507
+ }
508
+ return $pages;
509
+ }
510
+
511
+ // Modifies the feed link to add the language parameter
512
+ // FIXME should be an option to do this ?
513
+ function feed_link($url, $feed) {
514
+ global $wp_rewrite;
515
+ $options = get_option('polylang');
516
+
517
+ if ($this->curlang) {
518
+ if ($wp_rewrite->using_permalinks()) {
519
+ $home = home_url();
520
+ $options['rewrite'] ? $base = '/' : $base = '/language/';
521
+ $url = str_replace($home, $home.$base.$this->curlang->slug, $url);
522
+ }
523
+ else {
524
+ if ($feed)
525
+ $url = home_url('?lang='.$this->curlang->slug.'&feed='.$feed);
526
+ }
527
+ }
528
+ return $url;
529
+ }
530
+
531
+ // modifies the sql request for wp_get_archives an get_adjacent_post to filter by the current language
532
+ function posts_join($sql) {
533
+ if ($this->curlang) {
534
+ global $wpdb;
535
+ $sql .= " INNER JOIN $wpdb->term_relationships ON object_id = ID";
536
+ }
537
+ return $sql;
538
+ }
539
+
540
+ // modifies the sql request for wp_get_archives and get_adjacent_post to filter by the current language
541
+ function posts_where($sql) {
542
+ if ($this->curlang) {
543
+ global $wpdb;
544
+ $lang_id = $this->curlang->term_id;
545
+ $sql .= " AND term_taxonomy_id = $lang_id";
546
+ }
547
+ return $sql;
548
+ }
549
+
550
+ // modifies the archives link to add the language parameter
551
+ function get_archives_link($link_html) {
552
+ if ($this->curlang) {
553
+ global $wp_rewrite;
554
+ $options = get_option('polylang');
555
+ $home = home_url();
556
+ if ($wp_rewrite->using_permalinks()) {
557
+ $options['rewrite'] ? $base = '/' : $base = '/language/';
558
+ $link_html = str_replace($home, $home.$base.$this->curlang->slug, $link_html);
559
+ }
560
+ else
561
+ $link_html = str_replace($home.'/?', $home.'/?lang='.$this->curlang->slug.'&amp;', $link_html);
562
+ }
563
+ return $link_html;
564
+ }
565
+
566
+ // returns the url of the translation (if exists) of the current page
567
+ function get_translation_url($language) {
568
+
569
+ if ( is_single()) {
570
+ $id = $this->get_post(get_the_ID(), $language);
571
+ if ($id)
572
+ $url = get_permalink($id);
573
+ }
574
+
575
+ elseif ( is_page() ) {
576
+ $id = $this->get_post(get_the_ID(), $language);
577
+ if ($id)
578
+ $url = _get_page_link($id);
579
+ }
580
+
581
+ elseif ( is_category() || is_tag() ) {
582
+ $term = get_queried_object();
583
+ $term_id = $term->term_id;
584
+ $taxonomy = $term->taxonomy;
585
+ $lang = $this->get_term_language($term_id);
586
+
587
+ if ($language->slug == $lang->slug)
588
+ $url = get_term_link($term->slug, $taxonomy); // self link
589
+ else {
590
+ $link_id = $this->get_translated_term($term_id, $language);
591
+ if ($link_id) {
592
+ $term = get_term($link_id,$taxonomy); // We need the slug for get_term_link
593
+ $url = get_term_link($term->slug, $taxonomy);
594
+ }
595
+ }
596
+ }
597
+
598
+ // FIXME for date links, if I simply modify the lang query, there is a risk that there is no posts (if all are not translated at this date)
599
+ // do nothing for now
600
+ elseif ( is_year() ) {
601
+ }
602
+
603
+ elseif ( is_month() ) {
604
+ }
605
+
606
+ elseif (is_home() || is_tax('language') )
607
+ $url = get_term_link($language->slug, 'language');
608
+
609
+ return isset($url) ? $url : null;
610
+ }
611
+
612
+ // returns the home url in the right language
613
+ function get_home_url($language) {
614
+ $post_id = get_option('page_on_front');
615
+ if ($post_id) {
616
+ // a static page is used as front page
617
+ $id = $this->get_post($post_id, $language);
618
+ if($id)
619
+ $url = _get_page_link($id);
620
+ }
621
+ return isset($url) ? $url : get_term_link($language->slug, 'language');
622
+ }
623
+
624
+ // adds 'lang_url' as possible value to the 'show' parameter of bloginfo to display the home url in the correct language
625
+ // FIXME not tested
626
+ function bloginfo_url($output, $show) {
627
+ if ($show == 'lang_url' && $this->curlang) {
628
+ $url = $this->get_home_url($this->curlang);
629
+ $output = isset($url) ? $url : home_url('/');
630
+ }
631
+ return $output;
632
+ }
633
+
634
+ // Template tag : Displays links to the current page in other languages
635
+ // Usage : do_action('the_languages');
636
+ function the_languages() {
637
+ $listlanguages = $this->get_languages_list(true); // hides languages with no posts
638
+ $output = "<ul>\n";
639
+ foreach ($listlanguages as $language) {
640
+ $url = $this->get_translation_url($language);
641
+ if (!isset($url))
642
+ $url = $this->get_home_url($language); // if the page is not translated, link to the home page
643
+ $output .= "<li><a href='$url'>".$language->name."</a></li>\n";
644
+ }
645
+ $output .= "</ul>\n";
646
+ echo $output;
647
+ }
648
+
649
+ } // class Polylang
650
+
651
+ if (class_exists("Polylang"))
652
+ new Polylang();
653
+
654
+ ?>
post-metabox.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php // allowing to choose the post's language ?>
2
+ <p><em><?php $post_type == 'page' ? _e('Page\'s language:', 'polylang') : _e('Post\'s language:', 'polylang');?></em></p>
3
+ <p><?php
4
+ $listlanguages = $this->get_languages_list();
5
+ foreach ($listlanguages as $language) {
6
+ printf('<input type="radio" name="lang_choice" value="%s" id="%s" %s />', $language->slug, $language->slug, $language == $lang ? 'checked="checked"' : '');
7
+ printf('<label for %s"> %s</label><br />', $language->slug, $language->name);
8
+ } ?>
9
+ </p>
10
+
11
+ <?php // allowing to determine the linked posts
12
+ // FIXME inline CSS ! ?>
13
+ <p><em><?php _e('ID of posts in other languages:', 'polylang');?></em></p>
14
+ <table style="width: 100%; text-align: left; font-size: 11px; margin: 0 6px;">
15
+ <thead><tr>
16
+ <th><?php _e('Language', 'polylang');?></th>
17
+ <th><?php _e('Post ID', 'polylang');?></th>
18
+ <th><?php _e('Edit', 'polylang');?></th>
19
+ </tr></thead>
20
+
21
+ <tbody>
22
+ <?php foreach ($listlanguages as $language) {
23
+ if ($language != $lang) {
24
+ $value = $this->get_translated_post($post_ID, $language);
25
+ if (isset($_GET['from_post']))
26
+ $value = $this->get_post($_GET['from_post'], $language); ?>
27
+ <tr>
28
+ <td style="font-size: 11px;"><?php echo $language->name;?></td>
29
+ <td><input name="<?php echo $language->slug;?>" id="<?php echo $language->slug;?>" type="text" value="<?php echo $value;?>" size="6"/></td><?php
30
+ if ($lang) {
31
+ $link = $value ?
32
+ sprintf('<a href="post.php?action=edit&amp;post=%s">%s</a>', $value, __('Edit','polylang')) :
33
+ sprintf('<a href="post-new.php?from_post=%s&amp;new_lang=%s">%s</a>',$post_ID, $language->slug, __('Add new','polylang')); ?>
34
+ <td style="font-size: 11px;"><?php echo $link ?><td><?php
35
+ }?>
36
+ </tr><?php
37
+ }
38
+ } ?>
39
+ </tbody>
40
+ </table>
readme.txt ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Plugin Name ===
2
+ Contributors: Chouby
3
+ Tags: bilingual, multilingual, language, i18n, l10n, international
4
+ Requires at least: 3.1
5
+ Tested up to: 3.2.1
6
+ Stable tag: 0.1
7
+
8
+ Adds multilingual support to WordPress.
9
+
10
+ == Description ==
11
+
12
+ This plugin will not make the translation for you ! I you are looking for automatic translation, look for another plugin. Unlike some other plugins, Polylang does not integrate professionnal translation.
13
+
14
+ You write posts, pages and create categories and post tags as usual. You just have to define the language and it will be displayed only if the visitor is browsing this language. Optionaly, you can mark each post, page, category and post tag to be the translation of another one. Thus if, for example, your visitor is reading a post, it can switch (using the simple language switcher widget provided with the plugin) to the same post translated in another language (provided that you translated it !). There is no limit for the number of language.
15
+
16
+ Of course, the plugin itself is internationalized but is currently available only in English and in French.
17
+
18
+ Unlike some other plugins, if you deactivate Polylang, your blog will go on working as smoothly as possible. All your posts, pages, category and post tags would be accessible without language filter.
19
+
20
+ The tests have been made with WordPress 3.2.1 and with the Twenty Eleven theme (see FAQ). Although I did not test previous versions, I see no reason why it should not work with WordPress 3.1. However the plugin should not work with WordPress 3.0.5 and lower. Multisite has not been tested.
21
+
22
+ This is the initial version. Although I tested it carefully, there are probably still bugs. There are also lacking features. Remember that it is always better to test locally (or on a test server) that a plugin is fitting your needs before going in production. Note also that you must deactivate other multilingual plugins before activating Polylang. Otherwise, you may get unexpected results !
23
+
24
+ == Installation ==
25
+
26
+ 1. Download the plugin
27
+ 1. Extract all the files.
28
+ 1. Upload everything (keeping the directory structure) to the `/wp-content/plugins/` directory.
29
+ 1. Activate the plugin through the 'Plugins' menu in WordPress.
30
+ 1. Add the 'language switcher' Widget to let your visitors switch the language.
31
+ 1. Go to the languages settings page and create the languages you need
32
+ 1. Upload corresponding .mo files in WordPress languages directory (no need for English). You can download it from [here](http://svn.automattic.com/wordpress-i18n/). Take care that your theme must come with the corresponding .mo file too.
33
+
34
+ == Frequently Asked Questions ==
35
+
36
+ = Why using Polylang and not other well established equivalent plugins ? =
37
+
38
+ WPML: I tested only the last non-commercial version with WP 3.0.5. The plugin looks quite complete. It's however very heavy (almost 30000 lines of code !). The fact that it has turned commercial is probably adapted to companies or very active bloggers but not well adapted to small blogs.
39
+
40
+ Xili language: I tested the version 2.2.0. It looks too complex. For example you need to install 3 different plugins to manage post tags translation. If managing post translations is quite easy (and inspired Polylang...), the way to manage categories and post tags translations is not enough user friendly is my opinion. As WPML it's very heavy (about 12000 lines of code).
41
+
42
+ qtranslate: I tested the version 2.5.23. As claimed by its author, it's probably the best existing plugin... when using it. However, you must know that it is very difficult to come back to a clean site if you deactivate it (as, for example, one post in the database contains all translations). Moreover, it modifies urls so again, if you deactivate it, all links to your internal urls would be broken (not good for SEO).
43
+
44
+ In comparison to these plugins, Polylang tries to keep things simple and light, and does not mess your blog if you deactivate it. But it is still very young so be indulgent ;-)
45
+
46
+ = Language filter is lost when using the search form =
47
+
48
+ Your theme uses the template searchform.php (as Twenty Eleven does) or hardcoded the search form and javascript is disabled. Unfortunately Polylang currently does not support this. So you have the following alternatives to get the things work well:
49
+
50
+ * Use the 'get_search_form' function and place your custom search form in functions.php as described in the [codex](http://codex.wordpress.org/Function_Reference/get_search_form). The plugin also works well if you use the default search form provided by WordPress.
51
+ * Enable javascript (unfortunately you can't control this for your visitors so the first solution is better)
52
+
53
+ = Language filter is lost when using the calendar widget =
54
+
55
+ The plugin is not compatible with the calendar widget. The calendar displays well but it does not link to posts filtered in the right language. Consider using the Archives widget instead.
56
+
57
+ = The homepage link always send to the homepage in the default language =
58
+
59
+ Your theme has not been adapted to Polylang and both javascript and cookies are disabled. Unfortunately, it seems impossible (or too complex for me !) to correctly filter home_url (or bloginfo('url') and be sure that all things work. So you have the following alternatives:
60
+
61
+ * Use 'bloginfo('lang_url)' in your theme whenever you want to link to the homepage in the right language. Don't use this template tag for the search form action.
62
+ * Enable javascript and/or cookies (unfortunately you can't control this for your visitors so the first solution is better)
63
+
64
+ = I activated the plugin and my posts are not displayed any more =
65
+
66
+ You MUST define a language for all your posts and pages otherwise they will not pass the language filter...
67
+
68
+ = I activated the plugin and my categories and post tags are not displayed any more =
69
+
70
+ You MUST define a language for all your categories and post tags otherwise they will not pass the language filter...
71
+
72
+ == Changelog ==
73
+
74
+ = 0.1 =
75
+ * Initial release
76
+
uninstall.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ global $wpdb;
4
+ $wpdb->termmeta = $wpdb->prefix . 'termmeta'; // registers the termmeta table in wpdb
5
+ register_taxonomy('language', 'post', array('label' => false, 'query_var'=>'lang')); // temporarily register the language taxonomy
6
+
7
+ $languages = get_terms('language', array('hide_empty'=>false));
8
+ foreach ($languages as $lang) {
9
+ // delete references to this language in all posts
10
+ $args = array('numberposts'=> -1, 'post_type'=>'any', 'post_status'=>'any');
11
+ $posts = get_posts($args);
12
+ foreach ($posts as $post) {
13
+ delete_post_meta($post->ID, '_lang-'.$lang->slug);
14
+ }
15
+ // delete references to this language in categories & post tags
16
+ $terms = get_terms(array('category', 'post_tag'), 'get=all');
17
+ foreach ($terms as $term) {
18
+ delete_metadata('term', $term->term_id, '_language');
19
+ delete_metadata('term', $term->term_id, '_lang-'.$lang->slug);
20
+ }
21
+ // finally delete the language itself
22
+ wp_delete_term($lang->term_id, 'language');
23
+ }
24
+
25
+ // delete the termmeta table only if it is empty as other plugins may use it
26
+ $table = $wpdb->termmeta;
27
+ $count = $wpdb->get_var("SELECT COUNT(*) FROM $table;");
28
+ if (!$count) {
29
+ $wpdb->query("DROP TABLE $table;");
30
+ unset($wpdb->termmeta);
31
+ }
32
+
33
+ // finally delete options
34
+ delete_option('polylang');
35
+ delete_option('widget_polylang_widget');
36
+ ?>
widget.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Polylang_Widget extends WP_Widget {
4
+ function __construct() {
5
+ $widget_ops = array( 'description' => __( 'Displays a language switcher', 'polylang') );
6
+ parent::__construct('polylang', __('Language Switcher', 'polylang'), $widget_ops);
7
+ }
8
+
9
+ function widget($args, $instance) {
10
+ extract( $args );
11
+
12
+ echo "$before_widget\n";
13
+ do_action('the_languages');
14
+ echo "$after_widget\n";
15
+ }
16
+
17
+ } // Class Polylang_Widget
18
+
19
+ ?>