aboutsummaryrefslogtreecommitdiffhomepage
path: root/application/Languages.php
diff options
context:
space:
mode:
Diffstat (limited to 'application/Languages.php')
-rw-r--r--application/Languages.php169
1 files changed, 157 insertions, 12 deletions
diff --git a/application/Languages.php b/application/Languages.php
index c8b0a25a..3eb3388f 100644
--- a/application/Languages.php
+++ b/application/Languages.php
@@ -1,21 +1,166 @@
1<?php 1<?php
2 2
3namespace Shaarli;
4
5use Gettext\GettextTranslator;
6use Gettext\Merge;
7use Gettext\Translations;
8use Gettext\Translator;
9use Gettext\TranslatorInterface;
10use Shaarli\Config\ConfigManager;
11
3/** 12/**
4 * Wrapper function for translation which match the API 13 * Class Languages
5 * of gettext()/_() and ngettext(). 14 *
15 * Load Shaarli translations using 'gettext/gettext'.
16 * This class allows to either use PHP gettext extension, or a PHP implementation of gettext,
17 * with a fixed language, or dynamically using autoLocale().
6 * 18 *
7 * Not doing translation for now. 19 * Translation files PO/MO files follow gettext standard and must be placed under:
20 * <translation path>/<language>/LC_MESSAGES/<domain>.[po|mo]
8 * 21 *
9 * @param string $text Text to translate. 22 * Pros/cons:
10 * @param string $nText The plural message ID. 23 * - gettext extension is faster
11 * @param int $nb The number of items for plural forms. 24 * - gettext is very system dependent (PHP extension, the locale must be installed, and web server reloaded)
12 * 25 *
13 * @return String Text translated. 26 * Settings:
27 * - translation.mode:
28 * - auto: use default setting (PHP implementation)
29 * - php: use PHP implementation
30 * - gettext: use gettext wrapper
31 * - translation.language:
32 * - auto: use autoLocale() and the language change according to user HTTP headers
33 * - fixed language: e.g. 'fr'
34 * - translation.extensions:
35 * - domain => translation_path: allow plugins and themes to extend the defaut extension
36 * The domain must be unique, and translation path must be relative, and contains the tree mentioned above.
37 *
38 * @package Shaarli
14 */ 39 */
15function t($text, $nText = '', $nb = 0) { 40class Languages
16 if (empty($nText)) { 41{
17 return $text; 42 /**
43 * Core translations domain
44 */
45 const DEFAULT_DOMAIN = 'shaarli';
46
47 /**
48 * @var TranslatorInterface
49 */
50 protected $translator;
51
52 /**
53 * @var string
54 */
55 protected $language;
56
57 /**
58 * @var ConfigManager
59 */
60 protected $conf;
61
62 /**
63 * Languages constructor.
64 *
65 * @param string $language lang determined by autoLocale(), can be overridden.
66 * @param ConfigManager $conf instance.
67 */
68 public function __construct($language, $conf)
69 {
70 $this->conf = $conf;
71 $confLanguage = $this->conf->get('translation.language', 'auto');
72 // Auto mode or invalid parameter, use the detected language.
73 // If the detected language is invalid, it doesn't matter, it will use English.
74 if ($confLanguage === 'auto' || ! $this->isValidLanguage($confLanguage)) {
75 $this->language = substr($language, 0, 5);
76 } else {
77 $this->language = $confLanguage;
78 }
79
80 if (! extension_loaded('gettext')
81 || in_array($this->conf->get('translation.mode', 'auto'), ['auto', 'php'])
82 ) {
83 $this->initPhpTranslator();
84 } else {
85 $this->initGettextTranslator();
86 }
87
88 // Register default functions (e.g. '__()') to use our Translator
89 $this->translator->register();
90 }
91
92 /**
93 * Initialize the translator using php gettext extension (gettext dependency act as a wrapper).
94 */
95 protected function initGettextTranslator ()
96 {
97 $this->translator = new GettextTranslator();
98 $this->translator->setLanguage($this->language);
99 $this->translator->loadDomain(self::DEFAULT_DOMAIN, 'inc/languages');
100
101 foreach ($this->conf->get('translation.extensions', []) as $domain => $translationPath) {
102 if ($domain !== self::DEFAULT_DOMAIN) {
103 $this->translator->loadDomain($domain, $translationPath, false);
104 }
105 }
106 }
107
108 /**
109 * Initialize the translator using a PHP implementation of gettext.
110 *
111 * Note that if language po file doesn't exist, errors are ignored (e.g. not installed language).
112 */
113 protected function initPhpTranslator()
114 {
115 $this->translator = new Translator();
116 $translations = new Translations();
117 // Core translations
118 try {
119 /** @var Translations $translations */
120 $translations = $translations->addFromPoFile('inc/languages/'. $this->language .'/LC_MESSAGES/shaarli.po');
121 $translations->setDomain('shaarli');
122 $this->translator->loadTranslations($translations);
123 } catch (\InvalidArgumentException $e) {}
124
125
126 // Extension translations (plugins, themes, etc.).
127 foreach ($this->conf->get('translation.extensions', []) as $domain => $translationPath) {
128 if ($domain === self::DEFAULT_DOMAIN) {
129 continue;
130 }
131
132 try {
133 /** @var Translations $extension */
134 $extension = Translations::fromPoFile($translationPath . $this->language .'/LC_MESSAGES/'. $domain .'.po');
135 $extension->setDomain($domain);
136 $this->translator->loadTranslations($extension);
137 } catch (\InvalidArgumentException $e) {}
138 }
139 }
140
141 /**
142 * Checks if a language string is valid.
143 *
144 * @param string $language e.g. 'fr' or 'en_US'
145 *
146 * @return bool true if valid, false otherwise
147 */
148 protected function isValidLanguage($language)
149 {
150 return preg_match('/^[a-z]{2}(_[A-Z]{2})?/', $language) === 1;
151 }
152
153 /**
154 * Get the list of available languages for Shaarli.
155 *
156 * @return array List of available languages, with their label.
157 */
158 public static function getAvailableLanguages()
159 {
160 return [
161 'auto' => t('Automatic'),
162 'en' => t('English'),
163 'fr' => t('French'),
164 ];
18 } 165 }
19 $actualForm = $nb > 1 ? $nText : $text;
20 return sprintf($actualForm, $nb);
21} 166}