WordPress.org

Make WordPress Core

Ticket #26511: switch_to_locale__revisited.php

File switch_to_locale__revisited.php, 5.0 KB (added by tfrommen, 2 years ago)

A refreshed version of the WordPress.com functions - PHP 5.2 compatible, and object-oriented.

Line 
1<?php
2
3/**
4 * Simple single value storage with a getter.
5 */
6class WP_Locale_Storage {
7
8        /**
9         * @var string
10         */
11        private $locale;
12
13        /**
14         * Constructor. Stores the given locale.
15         *
16         * @param string $locale The locale.
17         */
18        public function __construct( $locale ) {
19
20                $this->locale = (string) $locale;
21        }
22
23        /**
24         * Returns the stored locale.
25         *
26         * @return string The stored locale.
27         */
28        public function get() {
29
30                return $this->locale;
31        }
32}
33
34/**
35 * Handles switching locales.
36 */
37class WP_Locale_Switcher {
38
39        /**
40         * @var callback[]
41         */
42        private $filters = array();
43
44        /**
45         * @var string[]
46         */
47        private $locales = array();
48
49        /**
50         * @var string
51         */
52        private $original_locale;
53
54        /**
55         * @var NOOP_Translations[][]
56         */
57        private $translations = array();
58
59        /**
60         * Constructor. Stores the original locale.
61         */
62        public function __construct() {
63
64                $this->original_locale = get_locale();
65        }
66
67        /**
68         * Switches the translations according to the given locale.
69         *
70         * @param string $locale The locale.
71         */
72        public function switch_to_locale( $locale ) {
73
74                $this->locales[] = $locale;
75
76                $current_locale = get_locale();
77                if ( $current_locale === $locale ) {
78                        return;
79                }
80
81                global $l10n;
82
83                $textdomains = array_keys( $l10n );
84
85                if ( ! $this->has_translations_for_locale( $current_locale ) ) {
86                        foreach ( $textdomains as $textdomain ) {
87                                $this->translations[ $current_locale ][ $textdomain ] = get_translations_for_domain( $textdomain );
88                        }
89                }
90
91                $this->remove_filters();
92
93                $this->add_filter_for_locale( $locale );
94
95                if ( $this->has_translations_for_locale( $locale ) ) {
96                        foreach ( $textdomains as $textdomain ) {
97                                if ( isset( $this->translations[ $locale ][ $textdomain ] ) ) {
98                                        $l10n[ $textdomain ] = $this->translations[ $locale ][ $textdomain ];
99                                }
100                        }
101                } else {
102                        foreach ( $textdomains as $textdomain ) {
103                                if ( 'default' === $textdomain ) {
104                                        load_default_textdomain();
105
106                                        continue;
107                                }
108
109                                unload_textdomain( $textdomain );
110
111                                /**
112                                 * TODO: Retrieve the MO file for the current textdomain.
113                                 *
114                                 * The current problem is, as yoavf said already, that the textdomain (string) alone doesn't carry
115                                 * enough information to determine if we have to call `load_plugin_textdomain()`, or something else.
116                                 * This could be easily fixed if we were to store the file in `MO::import_from_file()`.
117                                 */
118                                load_textdomain( $textdomain, $mofile );
119
120                                $this->translations[ $locale ][ $textdomain ] = get_translations_for_domain( $textdomain );
121                        }
122                }
123
124                $GLOBALS['wp_locale'] = new WP_Locale();
125        }
126
127        /**
128         * Restores the translations according to the previous locale.
129         *
130         * @return string|false Locale on success, false on error.
131         */
132        public function restore_locale() {
133
134                if ( ! array_pop( $this->locales ) ) {
135                        // The stack is empty, bail.
136                        return false;
137                }
138
139                $this->remove_filters();
140
141                if ( $locale = end( $this->locales ) ) {
142                        if ( isset( $filters[ $locale ] ) ) {
143                                add_filter( 'locale', $filters[ $locale ] );
144                        }
145                } else {
146                        // There's nothing left in the stack: go back to the original locale.
147                        $locale = $this->original_locale;
148                }
149
150                global $l10n;
151
152                foreach ( array_keys( $l10n ) as $textdomain ) {
153                        if ( isset( $this->translations[ $locale ][ $textdomain ] ) ) {
154                                $l10n[ $textdomain ] = $this->translations[ $locale ][ $textdomain ];
155                        }
156                }
157
158                $GLOBALS['wp_locale'] = new WP_Locale();
159
160                return $locale;
161        }
162
163        /**
164         * Checks if there are cached translations for the given locale.
165         *
166         * @param string $locale The locale.
167         *
168         * @return bool True if there are cached translations for the given locale, false otherwise.
169         */
170        private function has_translations_for_locale( $locale ) {
171
172                return ! empty( $this->translations[ $locale ] );
173        }
174
175        /**
176         * Removes all filter callbacks added before.
177         */
178        private function remove_filters() {
179
180                foreach ( $this->filters as $filter ) {
181                        remove_filter( 'locale', $filter );
182                }
183        }
184
185        /**
186         * Adds a filter callback returning the given locale.
187         *
188         * @param string $locale The locale.
189         */
190        private function add_filter_for_locale( $locale ) {
191
192                if ( ! isset( $this->filters[ $locale ] ) ) {
193                        // This really should be a closure, but ... well ... you know.
194                        $this->filters[ $locale ] = array( new WP_Locale_Storage( $locale ), 'get' );
195                }
196
197                add_filter( 'locale', $this->filters[ $locale ] );
198        }
199}
200
201$GLOBALS['wp_locale_switcher'] = new WP_Locale_Switcher();
202
203/**
204 * Switches the translations according to the given locale.
205 *
206 * @see WP_Locale_Switcher::switch_to_locale()
207 *
208 * @param string $locale The locale.
209 */
210function switch_to_locale( $locale ) {
211
212        /**
213         * @global WP_Locale_Switcher $wp_locale_switcher
214         */
215        global $wp_locale_switcher;
216
217        $wp_locale_switcher->switch_to_locale( $locale );
218}
219
220/**
221 * Restores the translations according to the previous locale.
222 *
223 * @see WP_Locale_Switcher::restore_locale()
224 *
225 * @return string|false Locale on success, false on error.
226 */
227function restore_locale() {
228
229        /**
230         * @global WP_Locale_Switcher $wp_locale_switcher
231         */
232        global $wp_locale_switcher;
233
234        return $wp_locale_switcher->restore_locale();
235}