Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace Drupal\locale;
|
Chris@0
|
4
|
Chris@18
|
5 use Drupal\Component\Gettext\PoItem;
|
Chris@0
|
6 use Drupal\Core\Cache\CacheBackendInterface;
|
Chris@0
|
7 use Drupal\Core\Cache\CacheCollector;
|
Chris@0
|
8 use Drupal\Core\Config\ConfigFactoryInterface;
|
Chris@0
|
9 use Drupal\Core\Language\LanguageManagerInterface;
|
Chris@0
|
10 use Drupal\Core\Lock\LockBackendInterface;
|
Chris@0
|
11 use Symfony\Component\HttpFoundation\RequestStack;
|
Chris@0
|
12
|
Chris@0
|
13 /**
|
Chris@0
|
14 * A cache collector to allow for dynamic building of the locale cache.
|
Chris@0
|
15 */
|
Chris@0
|
16 class LocaleLookup extends CacheCollector {
|
Chris@0
|
17
|
Chris@0
|
18 /**
|
Chris@0
|
19 * A language code.
|
Chris@0
|
20 *
|
Chris@0
|
21 * @var string
|
Chris@0
|
22 */
|
Chris@0
|
23 protected $langcode;
|
Chris@0
|
24
|
Chris@0
|
25 /**
|
Chris@0
|
26 * The msgctxt context.
|
Chris@0
|
27 *
|
Chris@0
|
28 * @var string
|
Chris@0
|
29 */
|
Chris@0
|
30 protected $context;
|
Chris@0
|
31
|
Chris@0
|
32 /**
|
Chris@0
|
33 * The locale storage.
|
Chris@0
|
34 *
|
Chris@0
|
35 * @var \Drupal\locale\StringStorageInterface
|
Chris@0
|
36 */
|
Chris@0
|
37 protected $stringStorage;
|
Chris@0
|
38
|
Chris@0
|
39 /**
|
Chris@0
|
40 * The cache backend that should be used.
|
Chris@0
|
41 *
|
Chris@0
|
42 * @var \Drupal\Core\Cache\CacheBackendInterface
|
Chris@0
|
43 */
|
Chris@0
|
44 protected $cache;
|
Chris@0
|
45
|
Chris@0
|
46 /**
|
Chris@0
|
47 * The lock backend that should be used.
|
Chris@0
|
48 *
|
Chris@0
|
49 * @var \Drupal\Core\Lock\LockBackendInterface
|
Chris@0
|
50 */
|
Chris@0
|
51 protected $lock;
|
Chris@0
|
52
|
Chris@0
|
53 /**
|
Chris@0
|
54 * The configuration factory.
|
Chris@0
|
55 *
|
Chris@0
|
56 * @var \Drupal\Core\Config\ConfigFactoryInterface
|
Chris@0
|
57 */
|
Chris@0
|
58 protected $configFactory;
|
Chris@0
|
59
|
Chris@0
|
60 /**
|
Chris@0
|
61 * The language manager.
|
Chris@0
|
62 *
|
Chris@0
|
63 * @var \Drupal\Core\Language\LanguageManagerInterface
|
Chris@0
|
64 */
|
Chris@0
|
65 protected $languageManager;
|
Chris@0
|
66
|
Chris@0
|
67 /**
|
Chris@0
|
68 * The request stack.
|
Chris@0
|
69 *
|
Chris@0
|
70 * @var \Symfony\Component\HttpFoundation\RequestStack
|
Chris@0
|
71 */
|
Chris@0
|
72 protected $requestStack;
|
Chris@0
|
73
|
Chris@0
|
74 /**
|
Chris@0
|
75 * Constructs a LocaleLookup object.
|
Chris@0
|
76 *
|
Chris@0
|
77 * @param string $langcode
|
Chris@0
|
78 * The language code.
|
Chris@0
|
79 * @param string $context
|
Chris@0
|
80 * The string context.
|
Chris@0
|
81 * @param \Drupal\locale\StringStorageInterface $string_storage
|
Chris@0
|
82 * The string storage.
|
Chris@0
|
83 * @param \Drupal\Core\Cache\CacheBackendInterface $cache
|
Chris@0
|
84 * The cache backend.
|
Chris@0
|
85 * @param \Drupal\Core\Lock\LockBackendInterface $lock
|
Chris@0
|
86 * The lock backend.
|
Chris@0
|
87 * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
Chris@0
|
88 * The config factory.
|
Chris@0
|
89 * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
|
Chris@0
|
90 * The language manager.
|
Chris@0
|
91 * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
|
Chris@0
|
92 * The request stack.
|
Chris@0
|
93 */
|
Chris@0
|
94 public function __construct($langcode, $context, StringStorageInterface $string_storage, CacheBackendInterface $cache, LockBackendInterface $lock, ConfigFactoryInterface $config_factory, LanguageManagerInterface $language_manager, RequestStack $request_stack) {
|
Chris@0
|
95 $this->langcode = $langcode;
|
Chris@0
|
96 $this->context = (string) $context;
|
Chris@0
|
97 $this->stringStorage = $string_storage;
|
Chris@0
|
98 $this->configFactory = $config_factory;
|
Chris@0
|
99 $this->languageManager = $language_manager;
|
Chris@0
|
100
|
Chris@0
|
101 $this->cache = $cache;
|
Chris@0
|
102 $this->lock = $lock;
|
Chris@0
|
103 $this->tags = ['locale'];
|
Chris@0
|
104 $this->requestStack = $request_stack;
|
Chris@0
|
105 }
|
Chris@0
|
106
|
Chris@0
|
107 /**
|
Chris@0
|
108 * {@inheritdoc}
|
Chris@0
|
109 */
|
Chris@0
|
110 protected function getCid() {
|
Chris@0
|
111 if (!isset($this->cid)) {
|
Chris@0
|
112 // Add the current user's role IDs to the cache key, this ensures that,
|
Chris@0
|
113 // for example, strings for admin menu items and settings forms are not
|
Chris@0
|
114 // cached for anonymous users.
|
Chris@0
|
115 $user = \Drupal::currentUser();
|
Chris@0
|
116 $rids = $user ? implode(':', $user->getRoles()) : '';
|
Chris@0
|
117 $this->cid = "locale:{$this->langcode}:{$this->context}:$rids";
|
Chris@0
|
118
|
Chris@0
|
119 // Getting the roles from the current user might have resulted in t()
|
Chris@0
|
120 // calls that attempted to get translations from the locale cache. In that
|
Chris@0
|
121 // case they would not go into this method again as
|
Chris@0
|
122 // CacheCollector::lazyLoadCache() already set the loaded flag. They would
|
Chris@0
|
123 // however call resolveCacheMiss() and add that string to the list of
|
Chris@0
|
124 // cache misses that need to be written into the cache. Prevent that by
|
Chris@0
|
125 // resetting that list. All that happens in such a case are a few uncached
|
Chris@0
|
126 // translation lookups.
|
Chris@0
|
127 $this->keysToPersist = [];
|
Chris@0
|
128 }
|
Chris@0
|
129 return $this->cid;
|
Chris@0
|
130 }
|
Chris@0
|
131
|
Chris@0
|
132 /**
|
Chris@0
|
133 * {@inheritdoc}
|
Chris@0
|
134 */
|
Chris@0
|
135 protected function resolveCacheMiss($offset) {
|
Chris@0
|
136 $translation = $this->stringStorage->findTranslation([
|
Chris@0
|
137 'language' => $this->langcode,
|
Chris@0
|
138 'source' => $offset,
|
Chris@0
|
139 'context' => $this->context,
|
Chris@0
|
140 ]);
|
Chris@0
|
141
|
Chris@0
|
142 if ($translation) {
|
Chris@0
|
143 $value = !empty($translation->translation) ? $translation->translation : TRUE;
|
Chris@0
|
144 }
|
Chris@0
|
145 else {
|
Chris@0
|
146 // We don't have the source string, update the {locales_source} table to
|
Chris@0
|
147 // indicate the string is not translated.
|
Chris@0
|
148 $this->stringStorage->createString([
|
Chris@0
|
149 'source' => $offset,
|
Chris@0
|
150 'context' => $this->context,
|
Chris@0
|
151 'version' => \Drupal::VERSION,
|
Chris@0
|
152 ])->addLocation('path', $this->requestStack->getCurrentRequest()->getRequestUri())->save();
|
Chris@0
|
153 $value = TRUE;
|
Chris@0
|
154 }
|
Chris@0
|
155
|
Chris@0
|
156 // If there is no translation available for the current language then use
|
Chris@0
|
157 // language fallback to try other translations.
|
Chris@0
|
158 if ($value === TRUE) {
|
Chris@0
|
159 $fallbacks = $this->languageManager->getFallbackCandidates(['langcode' => $this->langcode, 'operation' => 'locale_lookup', 'data' => $offset]);
|
Chris@0
|
160 if (!empty($fallbacks)) {
|
Chris@0
|
161 foreach ($fallbacks as $langcode) {
|
Chris@0
|
162 $translation = $this->stringStorage->findTranslation([
|
Chris@0
|
163 'language' => $langcode,
|
Chris@0
|
164 'source' => $offset,
|
Chris@0
|
165 'context' => $this->context,
|
Chris@0
|
166 ]);
|
Chris@0
|
167
|
Chris@0
|
168 if ($translation && !empty($translation->translation)) {
|
Chris@0
|
169 $value = $translation->translation;
|
Chris@0
|
170 break;
|
Chris@0
|
171 }
|
Chris@0
|
172 }
|
Chris@0
|
173 }
|
Chris@0
|
174 }
|
Chris@0
|
175
|
Chris@18
|
176 if (is_string($value) && strpos($value, PoItem::DELIMITER) !== FALSE) {
|
Chris@12
|
177 // Community translations imported from localize.drupal.org as well as
|
Chris@12
|
178 // migrated translations may contain @count[number].
|
Chris@12
|
179 $value = preg_replace('!@count\[\d+\]!', '@count', $value);
|
Chris@12
|
180 }
|
Chris@12
|
181
|
Chris@0
|
182 $this->storage[$offset] = $value;
|
Chris@0
|
183 // Disabling the usage of string caching allows a module to watch for
|
Chris@0
|
184 // the exact list of strings used on a page. From a performance
|
Chris@0
|
185 // perspective that is a really bad idea, so we have no user
|
Chris@0
|
186 // interface for this. Be careful when turning this option off!
|
Chris@0
|
187 if ($this->configFactory->get('locale.settings')->get('cache_strings')) {
|
Chris@0
|
188 $this->persist($offset);
|
Chris@0
|
189 }
|
Chris@0
|
190 return $value;
|
Chris@0
|
191 }
|
Chris@0
|
192
|
Chris@0
|
193 }
|