]> CyberLeo.Net >> Repos - Github/YOURLS.git/blob - includes/functions-l10n.php
Less code duplication, duh.
[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                 // YOURLS_LANG is defined in config.\r
42                 if ( defined( 'YOURLS_LANG' ) )\r
43                         $yourls_locale = YOURLS_LANG;\r
44 \r
45                 if ( empty( $yourls_locale ) )\r
46                         $yourls_locale = 'en_US';\r
47         }\r
48         return yourls_apply_filters( 'get_locale', $yourls_locale );\r
49 }\r
50 \r
51 /**\r
52  * Retrieves the translation of $text. If there is no translation, or\r
53  * the domain isn't loaded, the original text is returned.\r
54  *\r
55  * @see yourls__() Don't use yourls_translate() directly, use yourls__()\r
56  * @since 1.6\r
57  * @uses yourls_apply_filters() Calls 'translate' on domain translated text\r
58  *              with the untranslated text as second parameter.\r
59  *\r
60  * @param string $text Text to translate.\r
61  * @param string $domain Domain to retrieve the translated text.\r
62  * @return string Translated text\r
63  */\r
64 function yourls_translate( $text, $domain = 'default' ) {\r
65         $translations = yourls_get_translations_for_domain( $domain );\r
66         return yourls_apply_filters( 'translate', $translations->translate( $text ), $text, $domain );\r
67 }\r
68 \r
69 /**\r
70  * Retrieves the translation of $text with a given $context. If there is no translation, or\r
71  * the domain isn't loaded, the original text is returned.\r
72  *\r
73  * Quite a few times, there will be collisions with similar translatable text\r
74  * found in more than two places but with different translated context.\r
75  *\r
76  * By including the context in the pot file translators can translate the two\r
77  * strings differently.\r
78  *\r
79  * @since 1.6\r
80  * @param string $text Text to translate.\r
81  * @param string $context Context.\r
82  * @param string $domain Domain to retrieve the translated text.\r
83  * @return string Translated text\r
84  */\r
85 function yourls_translate_with_context( $text, $context, $domain = 'default' ) {\r
86         $translations = yourls_get_translations_for_domain( $domain );\r
87         return yourls_apply_filters( 'translate_with_context', $translations->translate( $text, $context ), $text, $context, $domain );\r
88 }\r
89 \r
90 /**\r
91  * Retrieves the translation of $text. If there is no translation, or\r
92  * the domain isn't loaded, the original text is returned.\r
93  *\r
94  * @see yourls_translate() An alias of yourls_translate()\r
95  * @since 1.6\r
96  *\r
97  * @param string $text Text to translate\r
98  * @param string $domain Optional. Domain to retrieve the translated text\r
99  * @return string Translated text\r
100  */\r
101 function yourls__( $text, $domain = 'default' ) {\r
102         return yourls_translate( $text, $domain );\r
103 }\r
104 \r
105 /**\r
106  * Return a translated sprintf() string (mix yourls__() and sprintf() in one func)\r
107  *\r
108  * Instead of doing sprintf( yourls__( 'string %s' ), $arg ) you can simply use:\r
109  * yourls_s( 'string %s', $arg )\r
110  * This function accepts an arbitrary number of arguments:\r
111  * - first one will be the string to translate, eg "hello %s my name is %s"\r
112  * - following ones will be the sprintf arguments, eg "world" and "Ozh"\r
113  * - if there are more arguments passed than needed, the last one will be used as the translation domain\r
114  * This function will not accept a textdomain argument: do not use in plugins or outside YOURLS core.\r
115  *\r
116  * @see sprintf()\r
117  * @since 1.6\r
118  *\r
119  * @param string $text Text to translate\r
120  * @param string $arg1, $arg2... Optional: sprintf tokens, and translation domain\r
121  * @return string Translated text\r
122  */\r
123 function yourls_s( $pattern ) {\r
124         // Get pattern and pattern arguments \r
125         $args = func_get_args();\r
126         // If yourls_s() called by yourls_se(), all arguments are wrapped in the same array key\r
127         if( count( $args ) == 1 && is_array( $args ) ) {\r
128                 $args = $args[0];\r
129         }\r
130         $pattern = $args[0];\r
131         \r
132         // get list of sprintf tokens (%s and such)\r
133         $num_of_tokens = substr_count( $pattern, '%' ) - 2 * substr_count( $pattern, '%%' );\r
134         \r
135         $domain = 'default';\r
136         // More arguments passed than needed for the sprintf? The last one will be the domain\r
137         if( $num_of_tokens < ( count( $args ) - 1 ) ) {\r
138                 $domain = array_pop( $args );\r
139         }\r
140         \r
141         // Translate text\r
142         $args[0] = yourls__( $pattern, $domain );\r
143         \r
144         return call_user_func_array( 'sprintf', $args );        \r
145 }\r
146 \r
147 /**\r
148  * Echo a translated sprintf() string (mix yourls__() and sprintf() in one func)\r
149  *\r
150  * Instead of doing printf( yourls__( 'string %s' ), $arg ) you can simply use:\r
151  * yourls_se( 'string %s', $arg )\r
152  * This function accepts an arbitrary number of arguments:\r
153  * - first one will be the string to translate, eg "hello %s my name is %s"\r
154  * - following ones will be the sprintf arguments, eg "world" and "Ozh"\r
155  * - if there are more arguments passed than needed, the last one will be used as the translation domain\r
156  *\r
157  * @see yourls_s()\r
158  * @see sprintf()\r
159  * @since 1.6\r
160  *\r
161  * @param string $text Text to translate\r
162  * @param string $arg1, $arg2... Optional: sprintf tokens, and translation domain\r
163  * @return string Translated text\r
164  */\r
165 function yourls_se( $pattern ) {\r
166         echo yourls_s( func_get_args() );\r
167 }\r
168 \r
169 \r
170 /**\r
171  * Retrieves the translation of $text and escapes it for safe use in an attribute.\r
172  * If there is no translation, or the domain isn't loaded, the original text is returned.\r
173  *\r
174  * @see yourls_translate() An alias of yourls_translate()\r
175  * @see yourls_esc_attr()\r
176  * @since 1.6\r
177  *\r
178  * @param string $text Text to translate\r
179  * @param string $domain Optional. Domain to retrieve the translated text\r
180  * @return string Translated text\r
181  */\r
182 function yourls_esc_attr__( $text, $domain = 'default' ) {\r
183         return yourls_esc_attr( yourls_translate( $text, $domain ) );\r
184 }\r
185 \r
186 /**\r
187  * Retrieves the translation of $text and escapes it for safe use in HTML output.\r
188  * If there is no translation, or the domain isn't loaded, the original text is returned.\r
189  *\r
190  * @see yourls_translate() An alias of yourls_translate()\r
191  * @see yourls_esc_html()\r
192  * @since 1.6\r
193  *\r
194  * @param string $text Text to translate\r
195  * @param string $domain Optional. Domain to retrieve the translated text\r
196  * @return string Translated text\r
197  */\r
198 function yourls_esc_html__( $text, $domain = 'default' ) {\r
199         return yourls_esc_html( yourls_translate( $text, $domain ) );\r
200 }\r
201 \r
202 /**\r
203  * Displays the returned translated text from yourls_translate().\r
204  *\r
205  * @see yourls_translate() Echoes returned yourls_translate() string\r
206  * @since 1.6\r
207  *\r
208  * @param string $text Text to translate\r
209  * @param string $domain Optional. Domain to retrieve the translated text\r
210  */\r
211 function yourls_e( $text, $domain = 'default' ) {\r
212         echo yourls_translate( $text, $domain );\r
213 }\r
214 \r
215 /**\r
216  * Displays translated text that has been escaped for safe use in an attribute.\r
217  *\r
218  * @see yourls_translate() Echoes returned yourls_translate() string\r
219  * @see yourls_esc_attr()\r
220  * @since 1.6\r
221  *\r
222  * @param string $text Text to translate\r
223  * @param string $domain Optional. Domain to retrieve the translated text\r
224  */\r
225 function yourls_esc_attr_e( $text, $domain = 'default' ) {\r
226         echo yourls_esc_attr( yourls_translate( $text, $domain ) );\r
227 }\r
228 \r
229 /**\r
230  * Displays translated text that has been escaped for safe use in HTML output.\r
231  *\r
232  * @see yourls_translate() Echoes returned yourls_translate() string\r
233  * @see yourls_esc_html()\r
234  * @since 1.6\r
235  *\r
236  * @param string $text Text to translate\r
237  * @param string $domain Optional. Domain to retrieve the translated text\r
238  */\r
239 function yourls_esc_html_e( $text, $domain = 'default' ) {\r
240         echo yourls_esc_html( yourls_translate( $text, $domain ) );\r
241 }\r
242 \r
243 /**\r
244  * Retrieve translated string with gettext context\r
245  *\r
246  * Quite a few times, there will be collisions with similar translatable text\r
247  * found in more than two places but with different translated context.\r
248  *\r
249  * By including the context in the pot file translators can translate the two\r
250  * strings differently.\r
251  *\r
252  * @since 1.6\r
253  *\r
254  * @param string $text Text to translate\r
255  * @param string $context Context information for the translators\r
256  * @param string $domain Optional. Domain to retrieve the translated text\r
257  * @return string Translated context string without pipe\r
258  */\r
259 function yourls_x( $text, $context, $domain = 'default' ) {\r
260         return yourls_translate_with_context( $text, $context, $domain );\r
261 }\r
262 \r
263 /**\r
264  * Displays translated string with gettext context\r
265  *\r
266  * @see yourls_x()\r
267  * @since 1.6\r
268  *\r
269  * @param string $text Text to translate\r
270  * @param string $context Context information for the translators\r
271  * @param string $domain Optional. Domain to retrieve the translated text\r
272  * @return string Translated context string without pipe\r
273  */\r
274 function yourls_ex( $text, $context, $domain = 'default' ) {\r
275         echo yourls_x( $text, $context, $domain );\r
276 }\r
277 \r
278 \r
279 /**\r
280  * Return translated text, with context, that has been escaped for safe use in an attribute\r
281  *\r
282  * @see yourls_translate() Return returned yourls_translate() string\r
283  * @see yourls_esc_attr()\r
284  * @see yourls_x()\r
285  * @since 1.6\r
286  *\r
287  * @param string $text Text to translate\r
288  * @param string $domain Optional. Domain to retrieve the translated text\r
289  */\r
290 function yourls_esc_attr_x( $single, $context, $domain = 'default' ) {\r
291         return yourls_esc_attr( yourls_translate_with_context( $single, $context, $domain ) );\r
292 }\r
293 \r
294 /**\r
295  * Return translated text, with context, that has been escaped for safe use in HTML output\r
296  *\r
297  * @see yourls_translate() Return returned yourls_translate() string\r
298  * @see yourls_esc_attr()\r
299  * @see yourls_x()\r
300  * @since 1.6\r
301  *\r
302  * @param string $text Text to translate\r
303  * @param string $domain Optional. Domain to retrieve the translated text\r
304  */\r
305 function yourls_esc_html_x( $single, $context, $domain = 'default' ) {\r
306         return yourls_esc_html( yourls_translate_with_context( $single, $context, $domain ) );\r
307 }\r
308 \r
309 /**\r
310  * Retrieve the plural or single form based on the amount.\r
311  *\r
312  * If the domain is not set in the $yourls_l10n list, then a comparison will be made\r
313  * and either $plural or $single parameters returned.\r
314  *\r
315  * If the domain does exist, then the parameters $single, $plural, and $number\r
316  * will first be passed to the domain's ngettext method. Then it will be passed\r
317  * to the 'translate_n' filter hook along with the same parameters. The expected\r
318  * type will be a string.\r
319  *\r
320  * @since 1.6\r
321  * @uses $yourls_l10n Gets list of domain translated string (gettext_reader) objects\r
322  * @uses yourls_apply_filters() Calls 'translate_n' hook on domains text returned,\r
323  *              along with $single, $plural, and $number parameters. Expected to return string.\r
324  *\r
325  * @param string $single The text that will be used if $number is 1\r
326  * @param string $plural The text that will be used if $number is not 1\r
327  * @param int $number The number to compare against to use either $single or $plural\r
328  * @param string $domain Optional. The domain identifier the text should be retrieved in\r
329  * @return string Either $single or $plural translated text\r
330  */\r
331 function yourls_n( $single, $plural, $number, $domain = 'default' ) {\r
332         $translations = yourls_get_translations_for_domain( $domain );\r
333         $translation = $translations->translate_plural( $single, $plural, $number );\r
334         return yourls_apply_filters( 'translate_n', $translation, $single, $plural, $number, $domain );\r
335 }\r
336 \r
337 /**\r
338  * A hybrid of yourls_n() and yourls_x(). It supports contexts and plurals.\r
339  *\r
340  * @since 1.6\r
341  * @see yourls_n()\r
342  * @see yourls_x()\r
343  *\r
344  */\r
345 function yourls_nx($single, $plural, $number, $context, $domain = 'default') {\r
346         $translations = yourls_get_translations_for_domain( $domain );\r
347         $translation = $translations->translate_plural( $single, $plural, $number, $context );\r
348         return yourls_apply_filters( 'translate_nx', $translation, $single, $plural, $number, $context, $domain );\r
349 }\r
350 \r
351 /**\r
352  * Register plural strings in POT file, but don't translate them.\r
353  *\r
354  * Used when you want to keep structures with translatable plural strings and\r
355  * use them later.\r
356  *\r
357  * Example:\r
358  *  $messages = array(\r
359  *      'post' => yourls_n_noop('%s post', '%s posts'),\r
360  *      'page' => yourls_n_noop('%s pages', '%s pages')\r
361  *  );\r
362  *  ...\r
363  *  $message = $messages[$type];\r
364  *  $usable_text = sprintf( yourls_translate_nooped_plural( $message, $count ), $count );\r
365  *\r
366  * @since 1.6\r
367  * @param string $singular Single form to be i18ned\r
368  * @param string $plural Plural form to be i18ned\r
369  * @param string $domain Optional. The domain identifier the text will be retrieved in\r
370  * @return array array($singular, $plural)\r
371  */\r
372 function yourls_n_noop( $singular, $plural, $domain = null ) {\r
373         return array(\r
374                 0 => $singular,\r
375                 1 => $plural, \r
376                 'singular' => $singular,\r
377                 'plural' => $plural,\r
378                 'context' => null,\r
379                 'domain' => $domain\r
380         );\r
381 }\r
382 \r
383 /**\r
384  * Register plural strings with context in POT file, but don't translate them.\r
385  *\r
386  * @since 1.6\r
387  * @see yourls_n_noop()\r
388  */\r
389 function yourls_nx_noop( $singular, $plural, $context, $domain = null ) {\r
390         return array(\r
391                 0 => $singular,\r
392                 1 => $plural,\r
393                 2 => $context,\r
394                 'singular' => $singular,\r
395                 'plural' => $plural,\r
396                 'context' => $context,\r
397                 'domain' => $domain\r
398         );\r
399 }\r
400 \r
401 /**\r
402  * Translate the result of yourls_n_noop() or yourls_nx_noop()\r
403  *\r
404  * @since 1.6\r
405  * @param array $nooped_plural Array with singular, plural and context keys, usually the result of yourls_n_noop() or yourls_nx_noop()\r
406  * @param int $count Number of objects\r
407  * @param string $domain Optional. The domain identifier the text should be retrieved in. If $nooped_plural contains\r
408  *      a domain passed to yourls_n_noop() or yourls_nx_noop(), it will override this value.\r
409  */\r
410 function yourls_translate_nooped_plural( $nooped_plural, $count, $domain = 'default' ) {\r
411         if ( $nooped_plural['domain'] )\r
412                 $domain = $nooped_plural['domain'];\r
413 \r
414         if ( $nooped_plural['context'] )\r
415                 return yourls_nx( $nooped_plural['singular'], $nooped_plural['plural'], $count, $nooped_plural['context'], $domain );\r
416         else\r
417                 return yourls_n( $nooped_plural['singular'], $nooped_plural['plural'], $count, $domain );\r
418 }\r
419 \r
420 /**\r
421  * Loads a MO file into the domain $domain.\r
422  *\r
423  * If the domain already exists, the translations will be merged. If both\r
424  * sets have the same string, the translation from the original value will be taken.\r
425  *\r
426  * On success, the .mo file will be placed in the $yourls_l10n global by $domain\r
427  * and will be a MO object.\r
428  *\r
429  * @since 1.6\r
430  * @uses $yourls_l10n Gets list of domain translated string objects\r
431  *\r
432  * @param string $domain Unique identifier for retrieving translated strings\r
433  * @param string $mofile Path to the .mo file\r
434  * @return bool True on success, false on failure\r
435  */\r
436 function yourls_load_textdomain( $domain, $mofile ) {\r
437         global $yourls_l10n;\r
438 \r
439         $plugin_override = yourls_apply_filters( 'override_load_textdomain', false, $domain, $mofile );\r
440 \r
441         if ( true == $plugin_override ) {\r
442                 return true;\r
443         }\r
444 \r
445         yourls_do_action( 'load_textdomain', $domain, $mofile );\r
446 \r
447         $mofile = yourls_apply_filters( 'load_textdomain_mofile', $mofile, $domain );\r
448 \r
449         if ( !is_readable( $mofile ) ) return false;\r
450 \r
451         $mo = new MO();\r
452         if ( !$mo->import_from_file( $mofile ) ) return false;\r
453 \r
454         if ( isset( $yourls_l10n[$domain] ) )\r
455                 $mo->merge_with( $yourls_l10n[$domain] );\r
456 \r
457         $yourls_l10n[$domain] = &$mo;\r
458 \r
459         return true;\r
460 }\r
461 \r
462 /**\r
463  * Unloads translations for a domain\r
464  *\r
465  * @since 1.6\r
466  * @param string $domain Textdomain to be unloaded\r
467  * @return bool Whether textdomain was unloaded\r
468  */\r
469 function yourls_unload_textdomain( $domain ) {\r
470         global $yourls_l10n;\r
471 \r
472         $plugin_override = yourls_apply_filters( 'override_unload_textdomain', false, $domain );\r
473 \r
474         if ( $plugin_override )\r
475                 return true;\r
476 \r
477         yourls_do_action( 'unload_textdomain', $domain );\r
478 \r
479         if ( isset( $yourls_l10n[$domain] ) ) {\r
480                 unset( $yourls_l10n[$domain] );\r
481                 return true;\r
482         }\r
483 \r
484         return false;\r
485 }\r
486 \r
487 /**\r
488  * Loads default translated strings based on locale.\r
489  *\r
490  * Loads the .mo file in YOURLS_LANG_DIR constant path from YOURLS root. The\r
491  * translated (.mo) file is named based on the locale.\r
492  *\r
493  * @since 1.6\r
494  */\r
495 function yourls_load_default_textdomain() {\r
496         $yourls_locale = yourls_get_locale();\r
497 \r
498         yourls_load_textdomain( 'default', YOURLS_LANG_DIR . "/$yourls_locale.mo" );\r
499 \r
500 }\r
501 \r
502 /**\r
503  * Returns the Translations instance for a domain. If there isn't one,\r
504  * returns empty Translations instance.\r
505  *\r
506  * @param string $domain\r
507  * @return object A Translation instance\r
508  */\r
509 function yourls_get_translations_for_domain( $domain ) {\r
510         global $yourls_l10n;\r
511         if ( !isset( $yourls_l10n[$domain] ) ) {\r
512                 $yourls_l10n[$domain] = new NOOP_Translations;\r
513         }\r
514         return $yourls_l10n[$domain];\r
515 }\r
516 \r
517 /**\r
518  * Whether there are translations for the domain\r
519  *\r
520  * @since 1.6\r
521  * @param string $domain\r
522  * @return bool Whether there are translations\r
523  */\r
524 function yourls_is_textdomain_loaded( $domain ) {\r
525         global $yourls_l10n;\r
526         return isset( $yourls_l10n[$domain] );\r
527 }\r
528 \r
529 /**\r
530  * Translates role name. Unused.\r
531  *\r
532  * Unused function for the moment, we'll see when there are roles.\r
533  * From the WP source: Since the role names are in the database and\r
534  * not in the source there are dummy gettext calls to get them into the POT\r
535  * file and this function properly translates them back.\r
536  *\r
537  * @since 1.6\r
538  */\r
539 function yourls_translate_user_role( $name ) {\r
540         return yourls_translate_with_context( $name, 'User role' );\r
541 }\r
542 \r
543 /**\r
544  * Get all available languages (*.mo files) in a given directory. The default directory is YOURLS_LANG_DIR.\r
545  *\r
546  * @since 1.6\r
547  *\r
548  * @param string $dir A directory in which to search for language files. The default directory is YOURLS_LANG_DIR.\r
549  * @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
550  */\r
551 function yourls_get_available_languages( $dir = null ) {\r
552         $languages = array();\r
553         \r
554         $dir = is_null( $dir) ? YOURLS_LANG_DIR : $dir;\r
555         \r
556         foreach( (array) glob( $dir . '/*.mo' ) as $lang_file ) {\r
557                 $languages[] = basename( $lang_file, '.mo' );\r
558         }\r
559         \r
560         return yourls_apply_filters( 'get_available_languages', $languages );\r
561 }\r
562 \r
563 /**\r
564  * Return integer number to format based on the locale.\r
565  *\r
566  * @since 1.6\r
567  *\r
568  * @param int $number The number to convert based on locale.\r
569  * @param int $decimals Precision of the number of decimal places.\r
570  * @return string Converted number in string format.\r
571  */\r
572 function yourls_number_format_i18n( $number, $decimals = 0 ) {\r
573     global $yourls_locale_formats;\r
574         if( !isset( $yourls_locale_formats ) )\r
575                 $yourls_locale_formats = new YOURLS_Locale_Formats();\r
576                 \r
577     $formatted = number_format( $number, abs( intval( $decimals ) ), $yourls_locale_formats->number_format['decimal_point'], $yourls_locale_formats->number_format['thousands_sep'] );\r
578     return yourls_apply_filters( 'number_format_i18n', $formatted );\r
579 }\r
580 \r
581 /**\r
582  * Return the date in localized format, based on timestamp.\r
583  *\r
584  * If the locale specifies the locale month and weekday, then the locale will\r
585  * take over the format for the date. If it isn't, then the date format string\r
586  * will be used instead.\r
587  *\r
588  * @since 1.6\r
589  *\r
590  * @param string $dateformatstring Format to display the date.\r
591  * @param int $unixtimestamp Optional. Unix timestamp.\r
592  * @param bool $gmt Optional, default is false. Whether to convert to GMT for time.\r
593  * @return string The date, translated if locale specifies it.\r
594  */\r
595 function yourls_date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) {\r
596     global $yourls_locale_formats;\r
597         if( !isset( $yourls_locale_formats ) )\r
598                 $yourls_locale_formats = new YOURLS_Locale_Formats();\r
599 \r
600         $i = $unixtimestamp;\r
601 \r
602     if ( false === $i ) {\r
603         if ( ! $gmt )\r
604             $i = current_time( 'timestamp' );\r
605         else\r
606             $i = time();\r
607         // we should not let date() interfere with our\r
608         // specially computed timestamp\r
609         $gmt = true;\r
610     }\r
611 \r
612     // store original value for language with untypical grammars\r
613     // see http://core.trac.wordpress.org/ticket/9396\r
614     $req_format = $dateformatstring;\r
615 \r
616     $datefunc = $gmt? 'gmdate' : 'date';\r
617 \r
618     if ( ( !empty( $yourls_locale_formats->month ) ) && ( !empty( $yourls_locale_formats->weekday ) ) ) {\r
619         $datemonth            = $yourls_locale_formats->get_month( $datefunc( 'm', $i ) );\r
620         $datemonth_abbrev     = $yourls_locale_formats->get_month_abbrev( $datemonth );\r
621         $dateweekday          = $yourls_locale_formats->get_weekday( $datefunc( 'w', $i ) );\r
622         $dateweekday_abbrev   = $yourls_locale_formats->get_weekday_abbrev( $dateweekday );\r
623         $datemeridiem         = $yourls_locale_formats->get_meridiem( $datefunc( 'a', $i ) );\r
624         $datemeridiem_capital = $yourls_locale_formats->get_meridiem( $datefunc( 'A', $i ) );\r
625                 \r
626         $dateformatstring = ' '.$dateformatstring;\r
627         $dateformatstring = preg_replace( "/([^\\\])D/", "\\1" . yourls_backslashit( $dateweekday_abbrev ), $dateformatstring );\r
628         $dateformatstring = preg_replace( "/([^\\\])F/", "\\1" . yourls_backslashit( $datemonth ), $dateformatstring );\r
629         $dateformatstring = preg_replace( "/([^\\\])l/", "\\1" . yourls_backslashit( $dateweekday ), $dateformatstring );\r
630         $dateformatstring = preg_replace( "/([^\\\])M/", "\\1" . yourls_backslashit( $datemonth_abbrev ), $dateformatstring );\r
631         $dateformatstring = preg_replace( "/([^\\\])a/", "\\1" . yourls_backslashit( $datemeridiem ), $dateformatstring );\r
632         $dateformatstring = preg_replace( "/([^\\\])A/", "\\1" . yourls_backslashit( $datemeridiem_capital ), $dateformatstring );\r
633 \r
634         $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 );\r
635     }\r
636     $timezone_formats = array( 'P', 'I', 'O', 'T', 'Z', 'e' );\r
637     $timezone_formats_re = implode( '|', $timezone_formats );\r
638     if ( preg_match( "/$timezone_formats_re/", $dateformatstring ) ) {\r
639         \r
640                 // TODO: implement a timezone option\r
641         $timezone_string = yourls_get_option( 'timezone_string' );\r
642         if ( $timezone_string ) {\r
643             $timezone_object = timezone_open( $timezone_string );\r
644             $date_object = date_create( null, $timezone_object );\r
645             foreach( $timezone_formats as $timezone_format ) {\r
646                 if ( false !== strpos( $dateformatstring, $timezone_format ) ) {\r
647                     $formatted = date_format( $date_object, $timezone_format );\r
648                     $dateformatstring = ' '.$dateformatstring;\r
649                     $dateformatstring = preg_replace( "/([^\\\])$timezone_format/", "\\1" . yourls_backslashit( $formatted ), $dateformatstring );\r
650                     $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 );\r
651                 }\r
652             }\r
653         }\r
654     }\r
655     $j = @$datefunc( $dateformatstring, $i );\r
656     // allow plugins to redo this entirely for languages with untypical grammars\r
657     $j = yourls_apply_filters('date_i18n', $j, $req_format, $i, $gmt);\r
658     return $j;\r
659 }\r
660 \r
661 /**\r
662  * Class that loads the calendar locale.\r
663  *\r
664  * @since 1.6\r
665  */\r
666 class YOURLS_Locale_Formats {\r
667         /**\r
668          * Stores the translated strings for the full weekday names.\r
669          *\r
670          * @since 1.6\r
671          * @var array\r
672          * @access private\r
673          */\r
674         var $weekday;\r
675 \r
676         /**\r
677          * Stores the translated strings for the one character weekday names.\r
678          *\r
679          * There is a hack to make sure that Tuesday and Thursday, as well\r
680          * as Sunday and Saturday, don't conflict. See init() method for more.\r
681          *\r
682          * @see YOURLS_Locale_Formats::init() for how to handle the hack.\r
683          *\r
684          * @since 1.6\r
685          * @var array\r
686          * @access private\r
687          */\r
688         var $weekday_initial;\r
689 \r
690         /**\r
691          * Stores the translated strings for the abbreviated weekday names.\r
692          *\r
693          * @since 1.6\r
694          * @var array\r
695          * @access private\r
696          */\r
697         var $weekday_abbrev;\r
698 \r
699         /**\r
700          * Stores the translated strings for the full month names.\r
701          *\r
702          * @since 1.6\r
703          * @var array\r
704          * @access private\r
705          */\r
706         var $month;\r
707 \r
708         /**\r
709          * Stores the translated strings for the abbreviated month names.\r
710          *\r
711          * @since 1.6\r
712          * @var array\r
713          * @access private\r
714          */\r
715         var $month_abbrev;\r
716 \r
717         /**\r
718          * Stores the translated strings for 'am' and 'pm'.\r
719          *\r
720          * Also the capitalized versions.\r
721          *\r
722          * @since 1.6\r
723          * @var array\r
724          * @access private\r
725          */\r
726         var $meridiem;\r
727 \r
728         /**\r
729          * The text direction of the locale language.\r
730          *\r
731          * Default is left to right 'ltr'.\r
732          *\r
733          * @since 1.6\r
734          * @var string\r
735          * @access private\r
736          */\r
737         var $text_direction = 'ltr';\r
738 \r
739         /**\r
740          * Sets up the translated strings and object properties.\r
741          *\r
742          * The method creates the translatable strings for various\r
743          * calendar elements. Which allows for specifying locale\r
744          * specific calendar names and text direction.\r
745          *\r
746          * @since 1.6\r
747          * @access private\r
748          */\r
749         function init() {\r
750                 // The Weekdays\r
751                 $this->weekday[0] = /* //translators: weekday */ yourls__( 'Sunday' );\r
752                 $this->weekday[1] = /* //translators: weekday */ yourls__( 'Monday' );\r
753                 $this->weekday[2] = /* //translators: weekday */ yourls__( 'Tuesday' );\r
754                 $this->weekday[3] = /* //translators: weekday */ yourls__( 'Wednesday' );\r
755                 $this->weekday[4] = /* //translators: weekday */ yourls__( 'Thursday' );\r
756                 $this->weekday[5] = /* //translators: weekday */ yourls__( 'Friday' );\r
757                 $this->weekday[6] = /* //translators: weekday */ yourls__( 'Saturday' );\r
758 \r
759                 // The first letter of each day. The _%day%_initial suffix is a hack to make\r
760                 // sure the day initials are unique.\r
761                 $this->weekday_initial[yourls__( 'Sunday' )]    = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'S_Sunday_initial' );\r
762                 $this->weekday_initial[yourls__( 'Monday' )]    = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'M_Monday_initial' );\r
763                 $this->weekday_initial[yourls__( 'Tuesday' )]   = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'T_Tuesday_initial' );\r
764                 $this->weekday_initial[yourls__( 'Wednesday' )] = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'W_Wednesday_initial' );\r
765                 $this->weekday_initial[yourls__( 'Thursday' )]  = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'T_Thursday_initial' );\r
766                 $this->weekday_initial[yourls__( 'Friday' )]    = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'F_Friday_initial' );\r
767                 $this->weekday_initial[yourls__( 'Saturday' )]  = /* //translators: one-letter abbreviation of the weekday */ yourls__( 'S_Saturday_initial' );\r
768 \r
769                 foreach ($this->weekday_initial as $weekday_ => $weekday_initial_) {\r
770                         $this->weekday_initial[$weekday_] = preg_replace('/_.+_initial$/', '', $weekday_initial_);\r
771                 }\r
772 \r
773                 // Abbreviations for each day.\r
774                 $this->weekday_abbrev[ yourls__( 'Sunday' ) ]    = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Sun' );\r
775                 $this->weekday_abbrev[ yourls__( 'Monday' ) ]    = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Mon' );\r
776                 $this->weekday_abbrev[ yourls__( 'Tuesday' ) ]   = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Tue' );\r
777                 $this->weekday_abbrev[ yourls__( 'Wednesday' ) ] = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Wed' );\r
778                 $this->weekday_abbrev[ yourls__( 'Thursday' ) ]  = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Thu' );\r
779                 $this->weekday_abbrev[ yourls__( 'Friday' ) ]    = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Fri' );\r
780                 $this->weekday_abbrev[ yourls__( 'Saturday' ) ]  = /* //translators: three-letter abbreviation of the weekday */ yourls__( 'Sat' );\r
781 \r
782                 // The Months\r
783                 $this->month['01'] = /* //translators: month name */ yourls__( 'January' );\r
784                 $this->month['02'] = /* //translators: month name */ yourls__( 'February' );\r
785                 $this->month['03'] = /* //translators: month name */ yourls__( 'March' );\r
786                 $this->month['04'] = /* //translators: month name */ yourls__( 'April' );\r
787                 $this->month['05'] = /* //translators: month name */ yourls__( 'May' );\r
788                 $this->month['06'] = /* //translators: month name */ yourls__( 'June' );\r
789                 $this->month['07'] = /* //translators: month name */ yourls__( 'July' );\r
790                 $this->month['08'] = /* //translators: month name */ yourls__( 'August' );\r
791                 $this->month['09'] = /* //translators: month name */ yourls__( 'September' );\r
792                 $this->month['10'] = /* //translators: month name */ yourls__( 'October' );\r
793                 $this->month['11'] = /* //translators: month name */ yourls__( 'November' );\r
794                 $this->month['12'] = /* //translators: month name */ yourls__( 'December' );\r
795 \r
796                 // Abbreviations for each month. Uses the same hack as above to get around the\r
797                 // 'May' duplication.\r
798                 $this->month_abbrev[ yourls__( 'January' ) ]   = /* //translators: three-letter abbreviation of the month */ yourls__( 'Jan_January_abbreviation' );\r
799                 $this->month_abbrev[ yourls__( 'February' ) ]  = /* //translators: three-letter abbreviation of the month */ yourls__( 'Feb_February_abbreviation' );\r
800                 $this->month_abbrev[ yourls__( 'March' ) ]     = /* //translators: three-letter abbreviation of the month */ yourls__( 'Mar_March_abbreviation' );\r
801                 $this->month_abbrev[ yourls__( 'April' ) ]     = /* //translators: three-letter abbreviation of the month */ yourls__( 'Apr_April_abbreviation' );\r
802                 $this->month_abbrev[ yourls__( 'May' ) ]       = /* //translators: three-letter abbreviation of the month */ yourls__( 'May_May_abbreviation' );\r
803                 $this->month_abbrev[ yourls__( 'June' ) ]      = /* //translators: three-letter abbreviation of the month */ yourls__( 'Jun_June_abbreviation' );\r
804                 $this->month_abbrev[ yourls__( 'July' ) ]      = /* //translators: three-letter abbreviation of the month */ yourls__( 'Jul_July_abbreviation' );\r
805                 $this->month_abbrev[ yourls__( 'August' ) ]    = /* //translators: three-letter abbreviation of the month */ yourls__( 'Aug_August_abbreviation' );\r
806                 $this->month_abbrev[ yourls__( 'September' ) ] = /* //translators: three-letter abbreviation of the month */ yourls__( 'Sep_September_abbreviation' );\r
807                 $this->month_abbrev[ yourls__( 'October' ) ]   = /* //translators: three-letter abbreviation of the month */ yourls__( 'Oct_October_abbreviation' );\r
808                 $this->month_abbrev[ yourls__( 'November' ) ]  = /* //translators: three-letter abbreviation of the month */ yourls__( 'Nov_November_abbreviation' );\r
809                 $this->month_abbrev[ yourls__( 'December' ) ]  = /* //translators: three-letter abbreviation of the month */ yourls__( 'Dec_December_abbreviation' );\r
810 \r
811                 foreach ($this->month_abbrev as $month_ => $month_abbrev_) {\r
812                         $this->month_abbrev[$month_] = preg_replace('/_.+_abbreviation$/', '', $month_abbrev_);\r
813                 }\r
814 \r
815                 // The Meridiems\r
816                 $this->meridiem['am'] = yourls__( 'am' );\r
817                 $this->meridiem['pm'] = yourls__( 'pm' );\r
818                 $this->meridiem['AM'] = yourls__( 'AM' );\r
819                 $this->meridiem['PM'] = yourls__( 'PM' );\r
820 \r
821                 // Numbers formatting\r
822                 // See http://php.net/number_format\r
823 \r
824                 /* //translators: $thousands_sep argument for http://php.net/number_format, default is , */\r
825                 $trans = yourls__( 'number_format_thousands_sep' );\r
826                 $this->number_format['thousands_sep'] = ('number_format_thousands_sep' == $trans) ? ',' : $trans;\r
827 \r
828                 /* //translators: $dec_point argument for http://php.net/number_format, default is . */\r
829                 $trans = yourls__( 'number_format_decimal_point' );\r
830                 $this->number_format['decimal_point'] = ('number_format_decimal_point' == $trans) ? '.' : $trans;\r
831 \r
832                 // Set text direction.\r
833                 if ( isset( $GLOBALS['text_direction'] ) )\r
834                         $this->text_direction = $GLOBALS['text_direction'];\r
835                 /* //translators: 'rtl' or 'ltr'. This sets the text direction for YOURLS. */\r
836                 elseif ( 'rtl' == yourls_x( 'ltr', 'text direction' ) )\r
837                         $this->text_direction = 'rtl';\r
838         }\r
839 \r
840         /**\r
841          * Retrieve the full translated weekday word.\r
842          *\r
843          * Week starts on translated Sunday and can be fetched\r
844          * by using 0 (zero). So the week starts with 0 (zero)\r
845          * and ends on Saturday with is fetched by using 6 (six).\r
846          *\r
847          * @since 1.6\r
848          * @access public\r
849          *\r
850          * @param int $weekday_number 0 for Sunday through 6 Saturday\r
851          * @return string Full translated weekday\r
852          */\r
853         function get_weekday( $weekday_number ) {\r
854                 return $this->weekday[ $weekday_number ];\r
855         }\r
856 \r
857         /**\r
858          * Retrieve the translated weekday initial.\r
859          *\r
860          * The weekday initial is retrieved by the translated\r
861          * full weekday word. When translating the weekday initial\r
862          * pay attention to make sure that the starting letter does\r
863          * not conflict.\r
864          *\r
865          * @since 1.6\r
866          * @access public\r
867          *\r
868          * @param string $weekday_name\r
869          * @return string\r
870          */\r
871         function get_weekday_initial( $weekday_name ) {\r
872                 return $this->weekday_initial[ $weekday_name ];\r
873         }\r
874 \r
875         /**\r
876          * Retrieve the translated weekday abbreviation.\r
877          *\r
878          * The weekday abbreviation is retrieved by the translated\r
879          * full weekday word.\r
880          *\r
881          * @since 1.6\r
882          * @access public\r
883          *\r
884          * @param string $weekday_name Full translated weekday word\r
885          * @return string Translated weekday abbreviation\r
886          */\r
887         function get_weekday_abbrev( $weekday_name ) {\r
888                 return $this->weekday_abbrev[ $weekday_name ];\r
889         }\r
890 \r
891         /**\r
892          * Retrieve the full translated month by month number.\r
893          *\r
894          * The $month_number parameter has to be a string\r
895          * because it must have the '0' in front of any number\r
896          * that is less than 10. Starts from '01' and ends at\r
897          * '12'.\r
898          *\r
899          * You can use an integer instead and it will add the\r
900          * '0' before the numbers less than 10 for you.\r
901          *\r
902          * @since 1.6\r
903          * @access public\r
904          *\r
905          * @param string|int $month_number '01' through '12'\r
906          * @return string Translated full month name\r
907          */\r
908         function get_month( $month_number ) {\r
909                 return $this->month[ sprintf( '%02s', $month_number ) ];                \r
910         }\r
911 \r
912         /**\r
913          * Retrieve translated version of month abbreviation string.\r
914          *\r
915          * The $month_name parameter is expected to be the translated or\r
916          * translatable version of the month.\r
917          *\r
918          * @since 1.6\r
919          * @access public\r
920          *\r
921          * @param string $month_name Translated month to get abbreviated version\r
922          * @return string Translated abbreviated month\r
923          */\r
924         function get_month_abbrev( $month_name ) {\r
925                 return $this->month_abbrev[ $month_name ];\r
926         }\r
927 \r
928         /**\r
929          * Retrieve translated version of meridiem string.\r
930          *\r
931          * The $meridiem parameter is expected to not be translated.\r
932          *\r
933          * @since 1.6\r
934          * @access public\r
935          *\r
936          * @param string $meridiem Either 'am', 'pm', 'AM', or 'PM'. Not translated version.\r
937          * @return string Translated version\r
938          */\r
939         function get_meridiem( $meridiem ) {\r
940                 return $this->meridiem[ $meridiem ];\r
941         }\r
942 \r
943         /**\r
944          * Global variables are deprecated. For backwards compatibility only.\r
945          *\r
946          * @deprecated For backwards compatibility only.\r
947          * @access private\r
948          *\r
949          * @since 1.6\r
950          */\r
951         function register_globals() {\r
952                 $GLOBALS['weekday']         = $this->weekday;\r
953                 $GLOBALS['weekday_initial'] = $this->weekday_initial;\r
954                 $GLOBALS['weekday_abbrev']  = $this->weekday_abbrev;\r
955                 $GLOBALS['month']           = $this->month;\r
956                 $GLOBALS['month_abbrev']    = $this->month_abbrev;\r
957         }\r
958 \r
959         /**\r
960          * Constructor which calls helper methods to set up object variables\r
961          *\r
962          * @uses YOURLS_Locale_Formats::init()\r
963          * @uses YOURLS_Locale_Formats::register_globals()\r
964          * @since 1.6\r
965          *\r
966          * @return YOURLS_Locale_Formats\r
967          */\r
968         function __construct() {\r
969                 $this->init();\r
970                 $this->register_globals();\r
971         }\r
972 \r
973         /**\r
974          * Checks if current locale is RTL.\r
975          *\r
976          * @since 3.0.0\r
977          * @return bool Whether locale is RTL.\r
978          */\r
979         function is_rtl() {\r
980                 return 'rtl' == $this->text_direction;\r
981         }\r
982 }\r
983 \r
984 /**\r
985  * Loads a custom translation file (for a plugin, a theme, a public interface...)\r
986  *\r
987  * The .mo file should be named based on the domain with a dash, and then the locale exactly,\r
988  * eg 'myplugin-pt_BR.mo'\r
989  *\r
990  * @since 1.6\r
991  *\r
992  * @param string $domain Unique identifier (the "domain") for retrieving translated strings\r
993  * @param string $path Full path to directory containing MO files.\r
994  */\r
995 function yourls_load_custom_textdomain( $domain, $path ) {\r
996         $locale = yourls_apply_filters( 'load_custom_textdomain', yourls_get_locale(), $domain );\r
997     $mofile = trim( $path, '/' ) . '/'. $domain . '-' . $locale . '.mo';\r
998 \r
999     return yourls_load_textdomain( $domain, $mofile );\r
1000 }\r
1001 \r