5 use Gettext\GettextTranslator
;
6 use Gettext\Translations
;
7 use Gettext\Translator
;
8 use Gettext\TranslatorInterface
;
9 use Shaarli\Config\ConfigManager
;
14 * Load Shaarli translations using 'gettext/gettext'.
15 * This class allows to either use PHP gettext extension, or a PHP implementation of gettext,
16 * with a fixed language, or dynamically using autoLocale().
18 * Translation files PO/MO files follow gettext standard and must be placed under:
19 * <translation path>/<language>/LC_MESSAGES/<domain>.[po|mo]
22 * - gettext extension is faster
23 * - gettext is very system dependent (PHP extension, the locale must be installed, and web server reloaded)
27 * - auto: use default setting (PHP implementation)
28 * - php: use PHP implementation
29 * - gettext: use gettext wrapper
30 * - translation.language:
31 * - auto: use autoLocale() and the language change according to user HTTP headers
32 * - fixed language: e.g. 'fr'
33 * - translation.extensions:
34 * - domain => translation_path: allow plugins and themes to extend the defaut extension
35 * The domain must be unique, and translation path must be relative, and contains the tree mentioned above.
42 * Core translations domain
44 public const DEFAULT_DOMAIN
= 'shaarli';
47 * @var TranslatorInterface
49 protected $translator;
62 * Languages constructor.
64 * @param string $language lang determined by autoLocale(), can be overridden.
65 * @param ConfigManager $conf instance.
67 public function __construct($language, $conf)
70 $confLanguage = $this->conf
->get('translation.language', 'auto');
71 // Auto mode or invalid parameter, use the detected language.
72 // If the detected language is invalid, it doesn't matter, it will use English.
73 if ($confLanguage === 'auto' || ! $this->isValidLanguage($confLanguage)) {
74 $this->language
= substr($language, 0, 5);
76 $this->language
= $confLanguage;
80 ! extension_loaded('gettext')
81 || in_array($this->conf
->get('translation.mode', 'auto'), ['auto', 'php'])
83 $this->initPhpTranslator();
85 $this->initGettextTranslator();
88 // Register default functions (e.g. '__()') to use our Translator
89 $this->translator
->register();
93 * Initialize the translator using php gettext extension (gettext dependency act as a wrapper).
95 protected function initGettextTranslator()
97 $this->translator
= new GettextTranslator();
98 $this->translator
->setLanguage($this->language
);
99 $this->translator
->loadDomain(self
::DEFAULT_DOMAIN
, 'inc/languages');
101 // Default extension translation from the current theme
102 $themeTransFolder = rtrim($this->conf
->get('raintpl_tpl'), '/') . '/' . $this->conf
->get('theme') . '/language';
103 if (is_dir($themeTransFolder)) {
104 $this->translator
->loadDomain($this->conf
->get('theme'), $themeTransFolder, false);
107 foreach ($this->conf
->get('translation.extensions', []) as $domain => $translationPath) {
108 if ($domain !== self
::DEFAULT_DOMAIN
) {
109 $this->translator
->loadDomain($domain, $translationPath, false);
115 * Initialize the translator using a PHP implementation of gettext.
117 * Note that if language po file doesn't exist, errors are ignored (e.g. not installed language).
119 protected function initPhpTranslator()
121 $this->translator
= new Translator();
122 $translations = new Translations();
125 $translations = $translations->addFromPoFile(
126 'inc/languages/' . $this->language
. '/LC_MESSAGES/shaarli.po'
128 $translations->setDomain('shaarli');
129 $this->translator
->loadTranslations($translations);
130 } catch (\InvalidArgumentException
$e) {
133 // Default extension translation from the current theme
134 $theme = $this->conf
->get('theme');
135 $themeTransFolder = rtrim($this->conf
->get('raintpl_tpl'), '/') . '/' . $theme . '/language';
136 if (is_dir($themeTransFolder)) {
138 $translations = Translations
::fromPoFile(
139 $themeTransFolder . '/' . $this->language
. '/LC_MESSAGES/' . $theme . '.po'
141 $translations->setDomain($theme);
142 $this->translator
->loadTranslations($translations);
143 } catch (\InvalidArgumentException
$e) {
147 // Extension translations (plugins, themes, etc.).
148 foreach ($this->conf
->get('translation.extensions', []) as $domain => $translationPath) {
149 if ($domain === self
::DEFAULT_DOMAIN
) {
154 $extension = Translations
::fromPoFile(
155 $translationPath . $this->language
. '/LC_MESSAGES/' . $domain . '.po'
157 $extension->setDomain($domain);
158 $this->translator
->loadTranslations($extension);
159 } catch (\InvalidArgumentException
$e) {
165 * Checks if a language string is valid.
167 * @param string $language e.g. 'fr' or 'en_US'
169 * @return bool true if valid, false otherwise
171 protected function isValidLanguage($language)
173 return preg_match('/^[a-z]{2}(_[A-Z]{2})?/', $language) === 1;
177 * Get the list of available languages for Shaarli.
179 * @return array List of available languages, with their label.
181 public static function getAvailableLanguages()
184 'auto' => t('Automatic'),
186 'en' => t('English'),
188 'jp' => t('Japanese'),
189 'ru' => t('Russian'),