]> git.immae.eu Git - github/shaarli/Shaarli.git/blame - application/Languages.php
Optimize and cleanup imports
[github/shaarli/Shaarli.git] / application / Languages.php
CommitLineData
edf3ff5a
A
1<?php
2
12266213
A
3namespace Shaarli;
4
5use Gettext\GettextTranslator;
12266213
A
6use Gettext\Translations;
7use Gettext\Translator;
8use Gettext\TranslatorInterface;
9use Shaarli\Config\ConfigManager;
10
edf3ff5a 11/**
12266213
A
12 * Class Languages
13 *
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().
edf3ff5a 17 *
12266213
A
18 * Translation files PO/MO files follow gettext standard and must be placed under:
19 * <translation path>/<language>/LC_MESSAGES/<domain>.[po|mo]
edf3ff5a 20 *
12266213
A
21 * Pros/cons:
22 * - gettext extension is faster
23 * - gettext is very system dependent (PHP extension, the locale must be installed, and web server reloaded)
edf3ff5a 24 *
12266213
A
25 * Settings:
26 * - translation.mode:
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.
36 *
37 * @package Shaarli
edf3ff5a 38 */
12266213
A
39class Languages
40{
41 /**
42 * Core translations domain
43 */
44 const DEFAULT_DOMAIN = 'shaarli';
45
46 /**
47 * @var TranslatorInterface
48 */
49 protected $translator;
50
51 /**
52 * @var string
53 */
54 protected $language;
55
56 /**
57 * @var ConfigManager
58 */
59 protected $conf;
60
61 /**
62 * Languages constructor.
63 *
f39580c6 64 * @param string $language lang determined by autoLocale(), can be overridden.
12266213
A
65 * @param ConfigManager $conf instance.
66 */
67 public function __construct($language, $conf)
68 {
69 $this->conf = $conf;
70 $confLanguage = $this->conf->get('translation.language', 'auto');
b7c412d4
A
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.
12266213
A
73 if ($confLanguage === 'auto' || ! $this->isValidLanguage($confLanguage)) {
74 $this->language = substr($language, 0, 5);
75 } else {
76 $this->language = $confLanguage;
77 }
78
79 if (! extension_loaded('gettext')
80 || in_array($this->conf->get('translation.mode', 'auto'), ['auto', 'php'])
81 ) {
82 $this->initPhpTranslator();
83 } else {
84 $this->initGettextTranslator();
85 }
86
87 // Register default functions (e.g. '__()') to use our Translator
88 $this->translator->register();
89 }
90
91 /**
92 * Initialize the translator using php gettext extension (gettext dependency act as a wrapper).
93 */
f211e417 94 protected function initGettextTranslator()
12266213
A
95 {
96 $this->translator = new GettextTranslator();
97 $this->translator->setLanguage($this->language);
98 $this->translator->loadDomain(self::DEFAULT_DOMAIN, 'inc/languages');
99
68c6afc5
A
100 // Default extension translation from the current theme
101 $themeTransFolder = rtrim($this->conf->get('raintpl_tpl'), '/') .'/'. $this->conf->get('theme') .'/language';
102 if (is_dir($themeTransFolder)) {
103 $this->translator->loadDomain($this->conf->get('theme'), $themeTransFolder, false);
104 }
105
12266213
A
106 foreach ($this->conf->get('translation.extensions', []) as $domain => $translationPath) {
107 if ($domain !== self::DEFAULT_DOMAIN) {
108 $this->translator->loadDomain($domain, $translationPath, false);
109 }
110 }
111 }
112
113 /**
114 * Initialize the translator using a PHP implementation of gettext.
115 *
116 * Note that if language po file doesn't exist, errors are ignored (e.g. not installed language).
117 */
118 protected function initPhpTranslator()
119 {
120 $this->translator = new Translator();
121 $translations = new Translations();
122 // Core translations
123 try {
12266213
A
124 $translations = $translations->addFromPoFile('inc/languages/'. $this->language .'/LC_MESSAGES/shaarli.po');
125 $translations->setDomain('shaarli');
126 $this->translator->loadTranslations($translations);
f211e417
V
127 } catch (\InvalidArgumentException $e) {
128 }
12266213 129
68c6afc5
A
130 // Default extension translation from the current theme
131 $theme = $this->conf->get('theme');
132 $themeTransFolder = rtrim($this->conf->get('raintpl_tpl'), '/') .'/'. $theme .'/language';
133 if (is_dir($themeTransFolder)) {
134 try {
135 $translations = Translations::fromPoFile(
136 $themeTransFolder .'/'. $this->language .'/LC_MESSAGES/'. $theme .'.po'
137 );
138 $translations->setDomain($theme);
139 $this->translator->loadTranslations($translations);
f211e417
V
140 } catch (\InvalidArgumentException $e) {
141 }
68c6afc5 142 }
12266213
A
143
144 // Extension translations (plugins, themes, etc.).
145 foreach ($this->conf->get('translation.extensions', []) as $domain => $translationPath) {
146 if ($domain === self::DEFAULT_DOMAIN) {
147 continue;
148 }
149
150 try {
9d9f6d75
V
151 $extension = Translations::fromPoFile(
152 $translationPath . $this->language .'/LC_MESSAGES/'. $domain .'.po'
153 );
12266213
A
154 $extension->setDomain($domain);
155 $this->translator->loadTranslations($extension);
f211e417
V
156 } catch (\InvalidArgumentException $e) {
157 }
12266213
A
158 }
159 }
160
161 /**
162 * Checks if a language string is valid.
163 *
164 * @param string $language e.g. 'fr' or 'en_US'
165 *
166 * @return bool true if valid, false otherwise
167 */
168 protected function isValidLanguage($language)
169 {
170 return preg_match('/^[a-z]{2}(_[A-Z]{2})?/', $language) === 1;
edf3ff5a 171 }
f39580c6
A
172
173 /**
174 * Get the list of available languages for Shaarli.
175 *
176 * @return array List of available languages, with their label.
177 */
178 public static function getAvailableLanguages()
179 {
180 return [
181 'auto' => t('Automatic'),
182 'en' => t('English'),
183 'fr' => t('French'),
7ca12407 184 'de' => t('German'),
f39580c6
A
185 ];
186 }
edf3ff5a 187}