]> CyberLeo.Net >> Repos - Github/YOURLS.git/blob - includes/functions-l10n.php
Translation API! zomigod. First pass. See Issue 52.
[Github/YOURLS.git] / includes / functions-l10n.php
1 <?php\r
2 /**\r
3  * YOURLS Translation API\r
4  *\r
5  * YOURLS modification of a small subset from WordPress' Translation API implementation.\r
6  * GPL License\r
7  *\r
8  * @package POMO\r
9  * @subpackage i18n\r
10  */\r
11 \r
12 /**\r
13  * Load POMO files required to run library\r
14  */\r
15 require_once dirname(__FILE__) . '/pomo/mo.php';\r
16 require_once dirname(__FILE__) . '/pomo/translations.php';\r
17 \r
18 /**\r
19  * Gets the current locale.\r
20  *\r
21  * If the locale is set, then it will filter the locale in the 'get_locale' filter\r
22  * hook and return the value.\r
23  *\r
24  * If the locale is not set already, then the YOURLS_LANG constant is used if it is\r
25  * defined. Then it is filtered through the 'get_locale' filter hook and the value\r
26  * for the locale global set and the locale is returned.\r
27  *\r
28  * The process to get the locale should only be done once, but the locale will\r
29  * always be filtered using the 'get_locale' hook.\r
30  *\r
31  * @since 1.6\r
32  * @uses yourls_apply_filters() Calls 'get_locale' hook on locale value.\r
33  * @uses $yourls_locale Gets the locale stored in the global.\r
34  *\r
35  * @return string The locale of the blog or from the 'get_locale' hook.\r
36  */\r
37 function yourls_get_locale() {\r
38         global $yourls_locale;\r
39 \r
40         if ( isset( $yourls_locale ) )\r
41                 return yourls_apply_filters( 'get_locale', $yourls_locale );\r
42 \r
43         // YOURLS_LANG is defined in config.\r
44         if ( defined( 'YOURLS_LANG' ) )\r
45                 $yourls_locale = YOURLS_LANG;\r
46 \r
47         if ( empty( $yourls_locale ) )\r
48                 $yourls_locale = 'en_US';\r
49 \r
50         return yourls_apply_filters( 'get_locale', $yourls_locale );\r
51 }\r
52 \r
53 /**\r
54  * Retrieves the translation of $text. If there is no translation, or\r
55  * the domain isn't loaded, the original text is returned.\r
56  *\r
57  * @see yourls__() Don't use yourls_translate() directly, use yourls__()\r
58  * @since 1.6\r
59  * @uses yourls_apply_filters() Calls 'translate' on domain translated text\r
60  *              with the untranslated text as second parameter.\r
61  *\r
62  * @param string $text Text to translate.\r
63  * @param string $domain Domain to retrieve the translated text.\r
64  * @return string Translated text\r
65  */\r
66 function yourls_translate( $text, $domain = 'default' ) {\r
67         $translations = yourls_get_translations_for_domain( $domain );\r
68         return yourls_apply_filters( 'translate', $translations->translate( $text ), $text, $domain );\r
69 }\r
70 \r
71 /**\r
72  * Retrieves the translation of $text with a given $context. If there is no translation, or\r
73  * the domain isn't loaded, the original text is returned.\r
74  *\r
75  * Quite a few times, there will be collisions with similar translatable text\r
76  * found in more than two places but with different translated context.\r
77  *\r
78  * By including the context in the pot file translators can translate the two\r
79  * strings differently.\r
80  *\r
81  * @since 1.6\r
82  * @param string $text Text to translate.\r
83  * @param string $context Context.\r
84  * @param string $domain Domain to retrieve the translated text.\r
85  * @return string Translated text\r
86  */\r
87 function yourls_translate_with_context( $text, $context, $domain = 'default' ) {\r
88         $translations = yourls_get_translations_for_domain( $domain );\r
89         return yourls_apply_filters( 'translate_with_context', $translations->translate( $text, $context ), $text, $context, $domain );\r
90 }\r
91 \r
92 /**\r
93  * Retrieves the translation of $text. If there is no translation, or\r
94  * the domain isn't loaded, the original text is returned.\r
95  *\r
96  * @see yourls_translate() An alias of yourls_translate()\r
97  * @since 1.6\r
98  *\r
99  * @param string $text Text to translate\r
100  * @param string $domain Optional. Domain to retrieve the translated text\r
101  * @return string Translated text\r
102  */\r
103 function yourls__( $text, $domain = 'default' ) {\r
104         return yourls_translate( $text, $domain );\r
105 }\r
106 \r
107 /**\r
108  * Retrieves the translation of $text and escapes it for safe use in an attribute.\r
109  * If there is no translation, or the domain isn't loaded, the original text is returned.\r
110  *\r
111  * @see yourls_translate() An alias of yourls_translate()\r
112  * @see yourls_esc_attr()\r
113  * @since 1.6\r
114  *\r
115  * @param string $text Text to translate\r
116  * @param string $domain Optional. Domain to retrieve the translated text\r
117  * @return string Translated text\r
118  */\r
119 function yourls_esc_attr__( $text, $domain = 'default' ) {\r
120         return yourls_esc_attr( yourls_translate( $text, $domain ) );\r
121 }\r
122 \r
123 /**\r
124  * Retrieves the translation of $text and escapes it for safe use in HTML output.\r
125  * If there is no translation, or the domain isn't loaded, the original text is returned.\r
126  *\r
127  * @see yourls_translate() An alias of yourls_translate()\r
128  * @see yourls_esc_html()\r
129  * @since 1.6\r
130  *\r
131  * @param string $text Text to translate\r
132  * @param string $domain Optional. Domain to retrieve the translated text\r
133  * @return string Translated text\r
134  */\r
135 function yourls_esc_html__( $text, $domain = 'default' ) {\r
136         return yourls_esc_html( yourls_translate( $text, $domain ) );\r
137 }\r
138 \r
139 /**\r
140  * Displays the returned translated text from yourls_translate().\r
141  *\r
142  * @see yourls_translate() Echoes returned yourls_translate() string\r
143  * @since 1.6\r
144  *\r
145  * @param string $text Text to translate\r
146  * @param string $domain Optional. Domain to retrieve the translated text\r
147  */\r
148 function yourls_e( $text, $domain = 'default' ) {\r
149         echo yourls_translate( $text, $domain );\r
150 }\r
151 \r
152 /**\r
153  * Displays translated text that has been escaped for safe use in an attribute.\r
154  *\r
155  * @see yourls_translate() Echoes returned yourls_translate() string\r
156  * @see yourls_esc_attr()\r
157  * @since 1.6\r
158  *\r
159  * @param string $text Text to translate\r
160  * @param string $domain Optional. Domain to retrieve the translated text\r
161  */\r
162 function yourls_esc_attr_e( $text, $domain = 'default' ) {\r
163         echo yourls_esc_attr( yourls_translate( $text, $domain ) );\r
164 }\r
165 \r
166 /**\r
167  * Displays translated text that has been escaped for safe use in HTML output.\r
168  *\r
169  * @see yourls_translate() Echoes returned yourls_translate() string\r
170  * @see yourls_esc_html()\r
171  * @since 1.6\r
172  *\r
173  * @param string $text Text to translate\r
174  * @param string $domain Optional. Domain to retrieve the translated text\r
175  */\r
176 function yourls_esc_html_e( $text, $domain = 'default' ) {\r
177         echo yourls_esc_html( yourls_translate( $text, $domain ) );\r
178 }\r
179 \r
180 /**\r
181  * Retrieve translated string with gettext context\r
182  *\r
183  * Quite a few times, there will be collisions with similar translatable text\r
184  * found in more than two places but with different translated context.\r
185  *\r
186  * By including the context in the pot file translators can translate the two\r
187  * strings differently.\r
188  *\r
189  * @since 1.6\r
190  *\r
191  * @param string $text Text to translate\r
192  * @param string $context Context information for the translators\r
193  * @param string $domain Optional. Domain to retrieve the translated text\r
194  * @return string Translated context string without pipe\r
195  */\r
196 function yourls_x( $text, $context, $domain = 'default' ) {\r
197         return yourls_translate_with_context( $text, $context, $domain );\r
198 }\r
199 \r
200 /**\r
201  * Displays translated string with gettext context\r
202  *\r
203  * @see yourls_x()\r
204  * @since 1.6\r
205  *\r
206  * @param string $text Text to translate\r
207  * @param string $context Context information for the translators\r
208  * @param string $domain Optional. Domain to retrieve the translated text\r
209  * @return string Translated context string without pipe\r
210  */\r
211 function yourls_ex( $text, $context, $domain = 'default' ) {\r
212         echo yourls_x( $text, $context, $domain );\r
213 }\r
214 \r
215 \r
216 /**\r
217  * Return translated text, with context, that has been escaped for safe use in an attribute\r
218  *\r
219  * @see yourls_translate() Return returned yourls_translate() string\r
220  * @see yourls_esc_attr()\r
221  * @see yourls_x()\r
222  * @since 1.6\r
223  *\r
224  * @param string $text Text to translate\r
225  * @param string $domain Optional. Domain to retrieve the translated text\r
226  */\r
227 function yourls_esc_attr_x( $single, $context, $domain = 'default' ) {\r
228         return yourls_esc_attr( yourls_translate_with_context( $single, $context, $domain ) );\r
229 }\r
230 \r
231 /**\r
232  * Return translated text, with context, that has been escaped for safe use in HTML output\r
233  *\r
234  * @see yourls_translate() Return returned yourls_translate() string\r
235  * @see yourls_esc_attr()\r
236  * @see yourls_x()\r
237  * @since 1.6\r
238  *\r
239  * @param string $text Text to translate\r
240  * @param string $domain Optional. Domain to retrieve the translated text\r
241  */\r
242 function yourls_esc_html_x( $single, $context, $domain = 'default' ) {\r
243         return yourls_esc_html( yourls_translate_with_context( $single, $context, $domain ) );\r
244 }\r
245 \r
246 /**\r
247  * Retrieve the plural or single form based on the amount.\r
248  *\r
249  * If the domain is not set in the $yourls_l10n list, then a comparison will be made\r
250  * and either $plural or $single parameters returned.\r
251  *\r
252  * If the domain does exist, then the parameters $single, $plural, and $number\r
253  * will first be passed to the domain's ngettext method. Then it will be passed\r
254  * to the 'translate_n' filter hook along with the same parameters. The expected\r
255  * type will be a string.\r
256  *\r
257  * @since 1.6\r
258  * @uses $yourls_l10n Gets list of domain translated string (gettext_reader) objects\r
259  * @uses yourls_apply_filters() Calls 'translate_n' hook on domains text returned,\r
260  *              along with $single, $plural, and $number parameters. Expected to return string.\r
261  *\r
262  * @param string $single The text that will be used if $number is 1\r
263  * @param string $plural The text that will be used if $number is not 1\r
264  * @param int $number The number to compare against to use either $single or $plural\r
265  * @param string $domain Optional. The domain identifier the text should be retrieved in\r
266  * @return string Either $single or $plural translated text\r
267  */\r
268 function yourls_n( $single, $plural, $number, $domain = 'default' ) {\r
269         $translations = yourls_get_translations_for_domain( $domain );\r
270         $translation = $translations->translate_plural( $single, $plural, $number );\r
271         return yourls_apply_filters( 'translate_n', $translation, $single, $plural, $number, $domain );\r
272 }\r
273 \r
274 /**\r
275  * A hybrid of yourls_n() and yourls_x(). It supports contexts and plurals.\r
276  *\r
277  * @since 1.6\r
278  * @see yourls_n()\r
279  * @see yourls_x()\r
280  *\r
281  */\r
282 function yourls_nx($single, $plural, $number, $context, $domain = 'default') {\r
283         $translations = yourls_get_translations_for_domain( $domain );\r
284         $translation = $translations->translate_plural( $single, $plural, $number, $context );\r
285         return yourls_apply_filters( 'translate_nx', $translation, $single, $plural, $number, $context, $domain );\r
286 }\r
287 \r
288 /**\r
289  * Register plural strings in POT file, but don't translate them.\r
290  *\r
291  * Used when you want to keep structures with translatable plural strings and\r
292  * use them later.\r
293  *\r
294  * Example:\r
295  *  $messages = array(\r
296  *      'post' => yourls_n_noop('%s post', '%s posts'),\r
297  *      'page' => yourls_n_noop('%s pages', '%s pages')\r
298  *  );\r
299  *  ...\r
300  *  $message = $messages[$type];\r
301  *  $usable_text = sprintf( yourls_translate_nooped_plural( $message, $count ), $count );\r
302  *\r
303  * @since 1.6\r
304  * @param string $singular Single form to be i18ned\r
305  * @param string $plural Plural form to be i18ned\r
306  * @param string $domain Optional. The domain identifier the text will be retrieved in\r
307  * @return array array($singular, $plural)\r
308  */\r
309 function yourls_n_noop( $singular, $plural, $domain = null ) {\r
310         return array(\r
311                 0 => $singular,\r
312                 1 => $plural, \r
313                 'singular' => $singular,\r
314                 'plural' => $plural,\r
315                 'context' => null,\r
316                 'domain' => $domain\r
317         );\r
318 }\r
319 \r
320 /**\r
321  * Register plural strings with context in POT file, but don't translate them.\r
322  *\r
323  * @since 1.6\r
324  * @see yourls_n_noop()\r
325  */\r
326 function yourls_nx_noop( $singular, $plural, $context, $domain = null ) {\r
327         return array(\r
328                 0 => $singular,\r
329                 1 => $plural,\r
330                 2 => $context,\r
331                 'singular' => $singular,\r
332                 'plural' => $plural,\r
333                 'context' => $context,\r
334                 'domain' => $domain\r
335         );\r
336 }\r
337 \r
338 /**\r
339  * Translate the result of yourls_n_noop() or yourls_nx_noop()\r
340  *\r
341  * @since 1.6\r
342  * @param array $nooped_plural Array with singular, plural and context keys, usually the result of yourls_n_noop() or yourls_nx_noop()\r
343  * @param int $count Number of objects\r
344  * @param string $domain Optional. The domain identifier the text should be retrieved in. If $nooped_plural contains\r
345  *      a domain passed to yourls_n_noop() or yourls_nx_noop(), it will override this value.\r
346  */\r
347 function yourls_translate_nooped_plural( $nooped_plural, $count, $domain = 'default' ) {\r
348         if ( $nooped_plural['domain'] )\r
349                 $domain = $nooped_plural['domain'];\r
350 \r
351         if ( $nooped_plural['context'] )\r
352                 return yourls_nx( $nooped_plural['singular'], $nooped_plural['plural'], $count, $nooped_plural['context'], $domain );\r
353         else\r
354                 return yourls_n( $nooped_plural['singular'], $nooped_plural['plural'], $count, $domain );\r
355 }\r
356 \r
357 /**\r
358  * Loads a MO file into the domain $domain.\r
359  *\r
360  * If the domain already exists, the translations will be merged. If both\r
361  * sets have the same string, the translation from the original value will be taken.\r
362  *\r
363  * On success, the .mo file will be placed in the $yourls_l10n global by $domain\r
364  * and will be a MO object.\r
365  *\r
366  * @since 1.6\r
367  * @uses $yourls_l10n Gets list of domain translated string objects\r
368  *\r
369  * @param string $domain Unique identifier for retrieving translated strings\r
370  * @param string $mofile Path to the .mo file\r
371  * @return bool True on success, false on failure\r
372  */\r
373 function yourls_load_textdomain( $domain, $mofile ) {\r
374         global $yourls_l10n;\r
375 \r
376         $plugin_override = yourls_apply_filters( 'override_load_textdomain', false, $domain, $mofile );\r
377 \r
378         if ( true == $plugin_override ) {\r
379                 return true;\r
380         }\r
381 \r
382         yourls_do_action( 'load_textdomain', $domain, $mofile );\r
383 \r
384         $mofile = yourls_apply_filters( 'load_textdomain_mofile', $mofile, $domain );\r
385 \r
386         if ( !is_readable( $mofile ) ) return false;\r
387 \r
388         $mo = new MO();\r
389         if ( !$mo->import_from_file( $mofile ) ) return false;\r
390 \r
391         if ( isset( $yourls_l10n[$domain] ) )\r
392                 $mo->merge_with( $yourls_l10n[$domain] );\r
393 \r
394         $yourls_l10n[$domain] = &$mo;\r
395 \r
396         return true;\r
397 }\r
398 \r
399 /**\r
400  * Unloads translations for a domain\r
401  *\r
402  * @since 1.6\r
403  * @param string $domain Textdomain to be unloaded\r
404  * @return bool Whether textdomain was unloaded\r
405  */\r
406 function yourls_unload_textdomain( $domain ) {\r
407         global $yourls_l10n;\r
408 \r
409         $plugin_override = yourls_apply_filters( 'override_unload_textdomain', false, $domain );\r
410 \r
411         if ( $plugin_override )\r
412                 return true;\r
413 \r
414         yourls_do_action( 'unload_textdomain', $domain );\r
415 \r
416         if ( isset( $yourls_l10n[$domain] ) ) {\r
417                 unset( $yourls_l10n[$domain] );\r
418                 return true;\r
419         }\r
420 \r
421         return false;\r
422 }\r
423 \r
424 /**\r
425  * Loads default translated strings based on locale.\r
426  *\r
427  * Loads the .mo file in YOURLS_LANG_DIR constant path from YOURLS root. The\r
428  * translated (.mo) file is named based on the locale.\r
429  *\r
430  * @since 1.6\r
431  */\r
432 function yourls_load_default_textdomain() {\r
433         $yourls_locale = yourls_get_locale();\r
434 \r
435         yourls_load_textdomain( 'default', YOURLS_LANG_DIR . "/$yourls_locale.mo" );\r
436 \r
437 }\r
438 \r
439 /**\r
440  * Returns the Translations instance for a domain. If there isn't one,\r
441  * returns empty Translations instance.\r
442  *\r
443  * @param string $domain\r
444  * @return object A Translation instance\r
445  */\r
446 function yourls_get_translations_for_domain( $domain ) {\r
447         global $yourls_l10n;\r
448         if ( !isset( $yourls_l10n[$domain] ) ) {\r
449                 $yourls_l10n[$domain] = new NOOP_Translations;\r
450         }\r
451         return $yourls_l10n[$domain];\r
452 }\r
453 \r
454 /**\r
455  * Whether there are translations for the domain\r
456  *\r
457  * @since 1.6\r
458  * @param string $domain\r
459  * @return bool Whether there are translations\r
460  */\r
461 function yourls_is_textdomain_loaded( $domain ) {\r
462         global $yourls_l10n;\r
463         return isset( $yourls_l10n[$domain] );\r
464 }\r
465 \r
466 /**\r
467  * Translates role name. Unused.\r
468  *\r
469  * Unused function for the moment, we'll see when there are roles.\r
470  * From the WP source: Since the role names are in the database and\r
471  * not in the source there are dummy gettext calls to get them into the POT\r
472  * file and this function properly translates them back.\r
473  *\r
474  * @since 1.6\r
475  */\r
476 function yourls_translate_user_role( $name ) {\r
477         return yourls_translate_with_context( $name, 'User role' );\r
478 }\r
479 \r
480 /**\r
481  * Get all available languages (*.mo files) in a given directory. The default directory is YOURLS_LANG_DIR.\r
482  *\r
483  * @since 1.6\r
484  *\r
485  * @param string $dir A directory in which to search for language files. The default directory is YOURLS_LANG_DIR.\r
486  * @return array Array of language codes or an empty array if no languages are present. Language codes are formed by stripping the .mo extension from the language file names.\r
487  */\r
488 function yourls_get_available_languages( $dir = null ) {\r
489         $languages = array();\r
490         \r
491         $dir = is_null( $dir) ? YOURLS_LANG_DIR : $dir;\r
492         \r
493         foreach( (array) glob( $dir . '/*.mo' ) as $lang_file ) {\r
494                 $languages[] = basename( $lang_file, '.mo' );\r
495         }\r
496         \r
497         return yourls_apply_filters( 'get_available_languages', $languages );\r
498 }\r