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