1<?php 2 3 4namespace ComboStrap; 5 6 7use ComboStrap\Meta\Api\Metadata; 8use ComboStrap\Meta\Api\MetadataText; 9use dokuwiki\Cache\Cache; 10 11class Lang extends MetadataText 12{ 13 14 public const PROPERTY_NAME = "lang"; 15 16 17 /** 18 * Process the lang attribute 19 * https://www.w3.org/International/questions/qa-html-language-declarations 20 * @param TagAttributes $attributes 21 * 22 * Language supported: 23 * http://www.iana.org/assignments/language-subtag-registry/language-subtag-registry 24 * 25 * Common Locale Data Repository 26 * http://cldr.unicode.org/ 27 * Data: 28 * * http://www.unicode.org/Public/cldr/ 29 * * https://github.com/unicode-cldr/ 30 * * https://github.com/unicode-org/cldr-json 31 * The ''dir'' data is known as the ''characterOrder'' 32 * 33 */ 34 public static function processLangAttribute(&$attributes) 35 { 36 37 38 /** 39 * Adding the lang attribute 40 * if set 41 */ 42 if ($attributes->hasComponentAttribute(self::PROPERTY_NAME)) { 43 $langValue = $attributes->getValueAndRemove(self::PROPERTY_NAME); 44 $attributes->addOutputAttributeValue("lang", $langValue); 45 46 $languageDataCache = new Cache("combo_" . $langValue, ".json"); 47 $cacheDataUsable = $languageDataCache->useCache(); 48 if (!$cacheDataUsable) { 49 50 // Language about the data 51 $downloadUrl = "https://raw.githubusercontent.com/unicode-org/cldr-json/master/cldr-json/cldr-misc-modern/main/$langValue/layout.json"; 52 53 if (PluginUtility::isDevOrTest()) { 54 // phpunit takes over and would catch and cache the error 55 $filePointer = fopen($downloadUrl, 'r'); 56 } else { 57 $filePointer = @fopen($downloadUrl, 'r'); 58 } 59 if ($filePointer != false) { 60 61 $numberOfByte = @file_put_contents($languageDataCache->cache, $filePointer); 62 if ($numberOfByte != false) { 63 LogUtility::msg("The new language data ($langValue) was downloaded", LogUtility::LVL_MSG_INFO, self::PROPERTY_NAME); 64 $cacheDataUsable = true; 65 } else { 66 LogUtility::msg("Internal error: The language data ($langValue) could no be written to ($languageDataCache->cache)", LogUtility::LVL_MSG_ERROR, self::PROPERTY_NAME); 67 } 68 69 } else { 70 71 // fopen(): Unable to find the wrapper "https" - did you forget to enable it when you configured PHP? 72 $error_get_last = error_get_last(); 73 $message = $error_get_last['message']; 74 LogUtility::msg("The data for the language ($langValue) could not be downloaded at (<a href=\"$downloadUrl\">$langValue</a>). Error: " . $message, LogUtility::LVL_MSG_ERROR, self::PROPERTY_NAME); 75 76 } 77 } 78 79 if ($cacheDataUsable) { 80 $jsonAsArray = true; 81 $languageData = json_decode(file_get_contents($languageDataCache->cache), $jsonAsArray); 82 if ($languageData == null) { 83 LogUtility::msg("We could not read the data from the language ($langValue). No direction was set.", LogUtility::LVL_MSG_ERROR, self::PROPERTY_NAME); 84 return; 85 } 86 $characterOrder = $languageData["main"][$langValue]["layout"]["orientation"]["characterOrder"]; 87 if ($characterOrder == "right-to-left") { 88 $attributes->addOutputAttributeValue("dir", "rtl"); 89 } else { 90 $attributes->addOutputAttributeValue("dir", "ltr"); 91 } 92 } else { 93 LogUtility::msg("The language direction cannot be set because no language data was found for the language ($langValue)", LogUtility::LVL_MSG_WARNING, self::PROPERTY_NAME); 94 } 95 96 } 97 98 } 99 100 public static function createForMarkup(MarkupPath $markup): Lang 101 { 102 $lang = new Lang(); 103 $lang->setResource($markup); 104 return $lang; 105 } 106 107 108 /** 109 * @throws ExceptionNotFound 110 */ 111 public static function createFromRequestedMarkup(): Lang 112 { 113 return self::createForMarkup(MarkupPath::createFromRequestedPage()); 114 } 115 116 /** 117 * Set the direction of the text 118 * The global lang direction (not yet inside the Lang class) 119 * @param string $string 120 * @return void 121 */ 122 public static function setDirection(string $string) 123 { 124 global $lang; 125 $lang["direction"] = $string; 126 } 127 128 public static function createFromValue(string $langValue): Lang 129 { 130 $lang = new Lang(); 131 $lang->value = $langValue; 132 return $lang; 133 } 134 135 static public function getTab(): ?string 136 { 137 return MetaManagerForm::TAB_LANGUAGE_VALUE; 138 } 139 140 /** 141 * @return string 142 */ 143 public function getValueOrDefault(): string 144 { 145 try { 146 return $this->getValue(); 147 } catch (ExceptionNotFound $e) { 148 return $this->getDefaultValue(); 149 } 150 } 151 152 153 /** 154 * @throws ExceptionCompile 155 */ 156 public function setFromStoreValue($value): Metadata 157 { 158 159 $this->validityCheck($value); 160 return parent::setFromStoreValue($value); 161 162 } 163 164 /** 165 * @param string|null $value 166 * @return Metadata 167 * @throws ExceptionCompile 168 */ 169 public function setValue($value): Metadata 170 { 171 $this->validityCheck($value); 172 return parent::setValue($value); 173 } 174 175 176 static public function getDescription(): string 177 { 178 return "The language of the page"; 179 } 180 181 static public function getLabel(): string 182 { 183 return "Language"; 184 } 185 186 public static function getName(): string 187 { 188 return self::PROPERTY_NAME; 189 } 190 191 static public function getPersistenceType(): string 192 { 193 return Metadata::PERSISTENT_METADATA; 194 } 195 196 static public function isMutable(): bool 197 { 198 return true; 199 } 200 201 /** 202 * @return string 203 */ 204 public function getDefaultValue(): string 205 { 206 return Site::getLang(); 207 } 208 209 /** 210 * @throws ExceptionCompile 211 */ 212 private function validityCheck($value) 213 { 214 if ($value === "" || $value === null) { 215 return; 216 } 217 if (!StringUtility::match($value, "^[a-zA-Z]{2}$")) { 218 throw new ExceptionCompile("The lang value ($value) for the page ($this) does not have two letters", $this->getCanonical()); 219 } 220 } 221 222 static public function getCanonical(): string 223 { 224 return "lang"; 225 } 226 227 public function getDirection() 228 { 229 /** 230 * TODO: should be base on the page value 231 * Search PHP and CLDR 232 * https://punic.github.io/ 233 * https://www.php.net/manual/en/book.intl.php 234 * 235 * Example: 236 * https://github.com/salarmehr/cosmopolitan 237 * use Salarmehr\Cosmopolitan\Cosmo; 238 * 239 * echo Cosmo::create('fa')->direction(); // rlt 240 * echo Cosmo::create('en')->direction(); // ltr 241 */ 242 return Site::getLangDirection(); 243 } 244 245 246 static public function isOnForm(): bool 247 { 248 return true; 249 } 250 251} 252