PluginProbe
Polylang / 3.5
Polylang v3.5
3.8.9 3.8.8 3.8.7 3.8.6 3.8.5 3.8.4 3.8.3 2.7 2.7.0.1 2.7.1 2.7.2 2.7.3 2.7.4 2.8 2.8.1 2.8.2 2.8.3 2.8.4 2.9 2.9.1 2.9.2 3.0 3.0.1 3.0.2 3.0.3 All 233 releases
polylang / include / olt-manager.php

olt-manager.php in Polylang 3.5, at include/olt-manager.php

255 lines 8.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package Polylang
4 */
5
6 /**
7 * It is best practice that plugins do nothing before plugins_loaded is fired
8 * so it is what Polylang intends to do
9 * but some plugins load their text domain as soon as loaded, thus before plugins_loaded is fired
10 * this class differs text domain loading until the language is defined
11 * either in a plugins_loaded action or in a wp action ( when the language is set from content on frontend )
12 *
13 * @since 1.2
14 */
15 class PLL_OLT_Manager {
16 /**
17 * Singleton instance
18 *
19 * @var PLL_OLT_Manager|null
20 */
21 protected static $instance;
22
23 /**
24 * Stores the default site locale before it is modified.
25 *
26 * @var string|null
27 */
28 protected $default_locale;
29
30 /**
31 * Stores all loaded text domains and mo files.
32 *
33 * @var string[][]
34 */
35 protected $list_textdomains = array();
36
37 /**
38 * Stores post types an taxonomies labels to translate.
39 *
40 * @var string[][]
41 */
42 public $labels = array();
43
44 /**
45 * Constructor: setups relevant filters
46 *
47 * @since 1.2
48 */
49 public function __construct() {
50 // Allows Polylang to be the first plugin loaded ;-)
51 add_filter( 'pre_update_option_active_plugins', array( $this, 'make_polylang_first' ) );
52 add_filter( 'pre_update_option_active_sitewide_plugins', array( $this, 'make_polylang_first' ) );
53
54 // Overriding load text domain only on front since WP 4.7.
55 if ( is_admin() && ! Polylang::is_ajax_on_front() ) {
56 return;
57 }
58
59 // Saves the default locale before we start any language manipulation
60 $this->default_locale = get_locale();
61
62 // Filters for text domain management
63 add_filter( 'load_textdomain_mofile', array( $this, 'load_textdomain_mofile' ), 10, 2 );
64 add_filter( 'gettext', array( $this, 'gettext' ), 10, 3 );
65 add_filter( 'gettext_with_context', array( $this, 'gettext_with_context' ), 10, 4 );
66
67 // Loads text domains
68 add_action( 'pll_language_defined', array( $this, 'load_textdomains' ), 2 ); // After PLL_Frontend::pll_language_defined
69 add_action( 'pll_no_language_defined', array( $this, 'load_textdomains' ) );
70 }
71
72 /**
73 * Access to the single instance of the class
74 *
75 * @since 1.7
76 *
77 * @return PLL_OLT_Manager
78 */
79 public static function instance() {
80 if ( empty( self::$instance ) ) {
81 self::$instance = new self();
82 }
83
84 return self::$instance;
85 }
86
87 /**
88 * Loads text domains
89 *
90 * @since 0.1
91 *
92 * @return void
93 */
94 public function load_textdomains() {
95 // Our load_textdomain_mofile filter has done its job. let's remove it before calling load_textdomain
96 remove_filter( 'load_textdomain_mofile', array( $this, 'load_textdomain_mofile' ) );
97 remove_filter( 'gettext', array( $this, 'gettext' ) );
98 remove_filter( 'gettext_with_context', array( $this, 'gettext_with_context' ) );
99 $new_locale = get_locale();
100
101 // Don't try to save time for en_US as some users have theme written in another language
102 // Now we can load all overridden text domains with the right language
103 if ( ! empty( $this->list_textdomains ) ) {
104 foreach ( $this->list_textdomains as $textdomain ) {
105 // Since WP 4.6, plugins translations are first loaded from wp-content/languages
106 if ( ! load_textdomain( $textdomain['domain'], str_replace( "{$this->default_locale}.mo", "$new_locale.mo", $textdomain['mo'] ) ) ) {
107 // Since WP 3.5 themes may store languages files in /wp-content/languages/themes
108 if ( ! load_textdomain( $textdomain['domain'], WP_LANG_DIR . "/themes/{$textdomain['domain']}-$new_locale.mo" ) ) {
109 // Since WP 3.7 plugins may store languages files in /wp-content/languages/plugins
110 load_textdomain( $textdomain['domain'], WP_LANG_DIR . "/plugins/{$textdomain['domain']}-$new_locale.mo" );
111 }
112 }
113 }
114 }
115
116 // First remove taxonomies and post_types labels that we don't need to translate
117 $taxonomies = get_taxonomies( array( '_pll' => true ) );
118 $post_types = get_post_types( array( '_pll' => true ) );
119
120 // We don't need to translate core taxonomies and post types labels when setting the language from the url
121 // As they will be translated when registered the second time
122 if ( ! did_action( 'setup_theme' ) ) {
123 $taxonomies = array_merge( get_taxonomies( array( '_builtin' => true ) ), $taxonomies );
124 $post_types = array_merge( get_post_types( array( '_builtin' => true ) ), $post_types );
125 }
126
127 // Translate labels of post types and taxonomies
128 foreach ( array_diff_key( $GLOBALS['wp_taxonomies'], array_flip( $taxonomies ) ) as $tax ) {
129 $this->translate_labels( $tax );
130 }
131 foreach ( array_diff_key( $GLOBALS['wp_post_types'], array_flip( $post_types ) ) as $pt ) {
132 $this->translate_labels( $pt );
133 }
134
135 // Act only if the language has not been set early ( before default textdomain loading and $wp_locale creation )
136 if ( did_action( 'after_setup_theme' ) ) {
137 // Reinitializes wp_locale for weekdays and months
138 unset( $GLOBALS['wp_locale'] );
139 $GLOBALS['wp_locale'] = new WP_Locale();
140 }
141
142 /**
143 * Fires after the post types and taxonomies labels have been translated
144 * This allows plugins to translate text the same way we do for post types and taxonomies labels
145 *
146 * @since 1.2
147 *
148 * @param array $labels list of strings to trnaslate
149 */
150 do_action_ref_array( 'pll_translate_labels', array( &$this->labels ) );
151
152 // Free memory.
153 $this->default_locale = null;
154 $this->list_textdomains = array();
155 $this->labels = array();
156 }
157
158 /**
159 * Saves all text domains in a table for later usage.
160 * It replaces the 'override_load_textdomain' filter previously used.
161 *
162 * @since 2.0.4
163 *
164 * @param string $mofile The translation file name.
165 * @param string $domain The text domain name.
166 * @return string
167 */
168 public function load_textdomain_mofile( $mofile, $domain ) {
169 // On multisite, 2 files are sharing the same domain so we need to distinguish them.
170 if ( 'default' === $domain && false !== strpos( $mofile, '/ms-' ) ) {
171 $this->list_textdomains['ms-default'] = array( 'mo' => $mofile, 'domain' => $domain );
172 } else {
173 $this->list_textdomains[ $domain ] = array( 'mo' => $mofile, 'domain' => $domain );
174 }
175 return ''; // Hack to prevent WP loading text domains as we will load them all later.
176 }
177
178 /**
179 * Saves post types and taxonomies labels for a later usage
180 *
181 * @since 0.9
182 *
183 * @param string $translation not used
184 * @param string $text string to translate
185 * @param string $domain text domain
186 * @return string unmodified $translation
187 */
188 public function gettext( $translation, $text, $domain ) {
189 if ( is_string( $text ) ) { // Avoid a warning with some buggy plugins which pass an array
190 $this->labels[ $text ] = array( 'domain' => $domain );
191 }
192 return $translation;
193 }
194
195 /**
196 * Saves post types and taxonomies labels for a later usage
197 *
198 * @since 0.9
199 *
200 * @param string $translation not used
201 * @param string $text string to translate
202 * @param string $context some comment to describe the context of string to translate
203 * @param string $domain text domain
204 * @return string unmodified $translation
205 */
206 public function gettext_with_context( $translation, $text, $context, $domain ) {
207 $this->labels[ $text ] = array( 'domain' => $domain, 'context' => $context );
208 return $translation;
209 }
210
211 /**
212 * Translates post types and taxonomies labels once the language is known.
213 *
214 * @since 0.9
215 *
216 * @param WP_Post_Type|WP_Taxonomy $type Either a post type or a taxonomy.
217 * @return void
218 */
219 public function translate_labels( $type ) {
220 // Use static array to avoid translating several times the same ( default ) labels
221 static $translated = array();
222
223 foreach ( (array) $type->labels as $key => $label ) {
224 if ( is_string( $label ) && isset( $this->labels[ $label ] ) ) {
225 if ( empty( $translated[ $label ] ) ) {
226 // PHPCS:disable WordPress.WP.I18n
227 $type->labels->$key = $translated[ $label ] = isset( $this->labels[ $label ]['context'] ) ?
228 _x( $label, $this->labels[ $label ]['context'], $this->labels[ $label ]['domain'] ) :
229 __( $label, $this->labels[ $label ]['domain'] );
230 // PHPCS:enable
231 }
232 else {
233 $type->labels->$key = $translated[ $label ];
234 }
235 }
236 }
237 }
238
239 /**
240 * Allows Polylang to be the first plugin loaded ;-).
241 *
242 * @since 1.2
243 *
244 * @param string[] $plugins List of active plugins.
245 * @return string[] List of active plugins.
246 */
247 public function make_polylang_first( $plugins ) {
248 if ( $key = array_search( POLYLANG_BASENAME, $plugins ) ) {
249 unset( $plugins[ $key ] );
250 array_unshift( $plugins, POLYLANG_BASENAME );
251 }
252 return $plugins;
253 }
254 }
255