PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backup, Restore, Migration & Clone / 4.9.1
WP STAGING – WordPress Backup, Restore, Migration & Clone v4.9.1
4.9.1 4.9.0 4.8.1 trunk 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.10.0 3.2.0 3.3.1 3.3.2 3.3.3 3.4.1 3.4.3 3.5.0 3.6.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4 4.0.0 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.8.0
wp-staging / Framework / Language / Language.php
wp-staging / Framework / Language Last commit date
Language.php 3 months ago
Language.php
263 lines
1 <?php
2
3 namespace WPStaging\Framework\Language;
4
5 use WPStaging\Framework\Facades\Hooks;
6
7 class Language
8 {
9 /** @var string */
10 const HOOK_LOAD_MO_FILES = 'wpstg.language.load_mo_files';
11
12 /** @var string */
13 const TEXT_DOMAIN = 'wp-staging';
14
15 const FILTER_PLUGIN_LOCALE = 'plugin_locale';
16
17 /**
18 * @return void
19 */
20 public function load()
21 {
22 /** @noinspection NullPointerExceptionInspection */
23 $pluginLangDirectory = WPSTG_PLUGIN_DIR . 'languages/';
24 $wpLangDirectory = $this->getLangDirectory();
25
26 if (function_exists('get_user_locale')) {
27 $locale = get_user_locale();
28 } else {
29 $locale = get_locale();
30 }
31
32 // Traditional WP plugin locale filter
33 $locale = apply_filters(self::FILTER_PLUGIN_LOCALE, $locale, self::TEXT_DOMAIN);
34 $localMoFile = $this->getLocalMoFile($locale);
35 $globalMoFile = $this->getGlobalMoFile($locale);
36 // Unfiltered mo file name
37 $actualMoFile = sprintf('%1$s-%2$s.mo', self::TEXT_DOMAIN, $locale);
38
39 // Setup paths to current locale file
40 $moFileLocal = $pluginLangDirectory . $localMoFile;
41 $moFilesGlobal = [];
42 if ($globalMoFile !== $actualMoFile) {
43 $moFilesGlobal[] = sprintf('%s/%s/%s', $wpLangDirectory, 'plugins', $actualMoFile);
44 }
45
46 $moFilesGlobal[] = sprintf('%s/%s/%s', $wpLangDirectory, 'plugins', $globalMoFile);
47
48 // Internal Use Only. Use for loading languages files
49 Hooks::callInternalHook(self::HOOK_LOAD_MO_FILES, [$locale, $moFileLocal, $moFilesGlobal]);
50 }
51
52 /**
53 * Get the language code of the current locale, e.g. de, en, it, etc.
54 * @return string
55 */
56 public function getLocaleLanguageCode(): string
57 {
58 if (function_exists('get_user_locale')) {
59 $locale = get_user_locale();
60 } else {
61 $locale = get_locale();
62 }
63 return substr($locale, 0, 2);
64 }
65
66 /**
67 * Map of locale prefixes/codes to the short code used in our .mo file names.
68 * Order matters: longer prefixes must come before shorter ones so that
69 * e.g. 'zh_CN' matches before a hypothetical 'zh_' entry, and 'pt_BR'
70 * matches before a hypothetical 'pt_' entry.
71 */
72 const LOCALE_TO_FILE_CODE = [
73 'de_' => 'de',
74 'es_' => 'es',
75 'fr_' => 'fr',
76 'it_' => 'it',
77 'nl_' => 'nl',
78 'pl_' => 'pl',
79 'ru_' => 'ru',
80 'tr_' => 'tr',
81 'pt_BR' => 'pt_BR',
82 'zh_CN' => 'zh_CN',
83 'ja' => 'ja',
84 ];
85
86 /**
87 * Map of short file codes to their full WordPress locale form used by global .mo files.
88 */
89 const FILE_CODE_TO_GLOBAL_LOCALE = [
90 'de' => 'de_DE',
91 'es' => 'es_ES',
92 'fr' => 'fr_FR',
93 'it' => 'it_IT',
94 'nl' => 'nl_NL',
95 'pl' => 'pl_PL',
96 'ru' => 'ru_RU',
97 'tr' => 'tr_TR',
98 'pt_BR' => 'pt_BR',
99 'zh_CN' => 'zh_CN',
100 'ja' => 'ja',
101 ];
102
103 /**
104 * Resolve a WordPress locale to the language code used in our bundled .mo files.
105 *
106 * @param string $locale
107 * @return string|null The resolved code, or null when no bundled translation exists.
108 */
109 private function resolveFileCode(string $locale)
110 {
111 foreach (self::LOCALE_TO_FILE_CODE as $prefix => $code) {
112 if (strpos($locale, $prefix) === 0 || $locale === $code) {
113 return $code;
114 }
115 }
116
117 return null;
118 }
119
120 protected function getLocalMoFile(string $locale): string
121 {
122 $code = $this->resolveFileCode($locale);
123 if ($code !== null) {
124 $locale = $code;
125 }
126
127 return sprintf('%1$s-%2$s.mo', self::TEXT_DOMAIN, $locale);
128 }
129
130 protected function getGlobalMoFile(string $locale): string
131 {
132 $code = $this->resolveFileCode($locale);
133 if ($code !== null && isset(self::FILE_CODE_TO_GLOBAL_LOCALE[$code])) {
134 $locale = self::FILE_CODE_TO_GLOBAL_LOCALE[$code];
135 }
136
137 return sprintf('%1$s-%2$s.mo', self::TEXT_DOMAIN, $locale);
138 }
139
140 /**
141 * Rewrite a checkout URL for the current locale.
142 * German locales (de_DE, de_AT, de_CH, de_DE_formal, …) use /de/kaufen/ instead of /checkout/.
143 */
144 public static function localizeCheckoutUrl(string $url): string
145 {
146 $locale = function_exists('get_user_locale') ? get_user_locale() : get_locale();
147 if (strpos($locale, 'de_') === 0) {
148 return str_replace('/checkout/', '/de/kaufen/', $url);
149 }
150
151 return $url;
152 }
153
154 /**
155 * Rewrite a pricing URL for the current locale.
156 * German locales use /de/#pricing instead of /#pricing.
157 */
158 public static function localizePricingUrl(string $url): string
159 {
160 $locale = function_exists('get_user_locale') ? get_user_locale() : get_locale();
161 if (strpos($locale, 'de_') === 0) {
162 return str_replace('wp-staging.com/#', 'wp-staging.com/de/#', $url);
163 }
164
165 return $url;
166 }
167
168 /**
169 * Rewrite the support URL for the current locale.
170 * German locales use /de/support/ instead of /support/.
171 */
172 public static function localizeSupportUrl(string $url): string
173 {
174 $locale = function_exists('get_user_locale') ? get_user_locale() : get_locale();
175 if (strpos($locale, 'de_') === 0) {
176 return str_replace('/support/', '/de/support/', $url);
177 }
178
179 return $url;
180 }
181
182 /**
183 * Rewrite a wp-staging.com homepage URL for the current locale.
184 * German locales insert /de/ after the domain.
185 */
186 public static function localizeHomepageUrl(string $url): string
187 {
188 $locale = function_exists('get_user_locale') ? get_user_locale() : get_locale();
189 if (strpos($locale, 'de_') === 0) {
190 return str_replace('wp-staging.com/', 'wp-staging.com/de/', $url);
191 }
192
193 return $url;
194 }
195
196 /**
197 * Rewrite any wp-staging.com URL for the current locale.
198 * Inserts /de/ after the domain for German locales.
199 * Works with bare URLs, URLs with paths, and fragment-only URLs like /#pricing.
200 */
201 public static function localizeUrl(string $url): string
202 {
203 $locale = function_exists('get_user_locale') ? get_user_locale() : get_locale();
204 if (strpos($locale, 'de_') !== 0) {
205 return $url;
206 }
207
208 if (strpos($url, 'wp-staging.com/de/') !== false) {
209 return $url;
210 }
211
212 return preg_replace(
213 '#(https?://wp-staging\.com)/?#',
214 '$1/de/',
215 $url,
216 1
217 );
218 }
219
220 /**
221 * Rewrite a wp-staging.com docs URL for the current locale.
222 * Handles articles where the German slug differs from the English one.
223 */
224 public static function localizeDocsUrl(string $url): string
225 {
226 $locale = function_exists('get_user_locale') ? get_user_locale() : get_locale();
227 if (strpos($locale, 'de_') !== 0) {
228 return $url;
229 }
230
231 $germanDocsMap = [
232 'https://wp-staging.com/docs/how-to-migrate-your-wordpress-site-to-a-new-host/' => 'https://wp-staging.com/de/docs/wordpress-seite-zu-anderem-host-migrieren/',
233 'https://wp-staging.com/docs/documentation/' => 'https://wp-staging.com/de/docs/dokumentation/',
234 'https://wp-staging.com/docs/set-up-wp-staging-cli/' => 'https://wp-staging.com/de/docs/lokale-kopie-deiner-wordpress-seite-erstellen/',
235 'https://wp-staging.com/docs/pull-a-wordpress-site-from-one-server-to-another/' => 'https://wp-staging.com/de/docs/wordpress-seite-von-einem-server-auf-einen-anderen-ziehen/',
236 ];
237
238 // Strip fragment for lookup, re-append after
239 $fragment = '';
240 $hashPos = strpos($url, '#');
241 if ($hashPos !== false) {
242 $fragment = substr($url, $hashPos);
243 $baseUrl = substr($url, 0, $hashPos);
244 } else {
245 $baseUrl = $url;
246 }
247
248 if (isset($germanDocsMap[$baseUrl])) {
249 return $germanDocsMap[$baseUrl] . $fragment;
250 }
251
252 return self::localizeUrl($url);
253 }
254
255 /**
256 * @return string
257 */
258 protected function getLangDirectory(): string
259 {
260 return WP_LANG_DIR;
261 }
262 }
263