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