multilingual.class.php 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  1. <?php
  2. if (!defined('IN_ONLINE')) {
  3. exit('Access Denied');
  4. }
  5. /**
  6. * Description of multilingual
  7. *
  8. * @author Administrator
  9. */
  10. class multilingual{
  11. private static $_multilingual;
  12. function __construct() {
  13. }
  14. public static function getInstance() {
  15. global $memory_limit;
  16. $memory_limit = ini_get("memory_limit");
  17. ini_set("memory_limit", '2048M');
  18. if (!self::$_multilingual) {
  19. $c = __CLASS__;
  20. self::$_multilingual = new $c;
  21. }
  22. return self::$_multilingual;
  23. }
  24. public function multilingual_config() {
  25. $operate = utils::_get('operate');
  26. $operate = strtolower($operate);
  27. /*
  28. * multilingual_page_load
  29. */
  30. if ($operate == "multilingual_page") {
  31. //查询指定语言
  32. $langIds = [];
  33. $langkey = $_POST['langkey'];
  34. // 1. 统一处理 $langs 数组
  35. if (empty($langkey) || strtoupper($langkey) == "ALL") {
  36. // 如果没传或传 ALL,直接查询所有激活语言的 ID
  37. // 优化点:直接查 id,不需要先查 key 再查 id
  38. $langSql = "SELECT id FROM public.kln_i18n_languages";
  39. $langRows = common::excuteListSql($langSql);
  40. if ($langRows) {
  41. $langIds = array_column($langRows, 'id');
  42. }
  43. } else {
  44. // 2. 如果指定了语言,使用 IN 查询一次性获取
  45. $langs = explode(',', $langkey);
  46. // 安全过滤:防止 SQL 注入,并确保只处理非空字符串
  47. $safeLangs = array();
  48. foreach ($langs as $l) {
  49. $l = trim($l);
  50. if (!empty($l)) {
  51. $safeLangs[] = "'" . common::check_input($l) . "'";
  52. }
  53. }
  54. if (!empty($safeLangs)) {
  55. // 拼接 IN 条件:('english', 'french')
  56. $inClause = implode(',', $safeLangs);
  57. $langSql = "SELECT id FROM public.kln_i18n_languages WHERE lang_key IN ($inClause)";
  58. $langRows = common::excuteListSql($langSql);
  59. if ($langRows) {
  60. $langIds = array_column($langRows, 'id');
  61. }
  62. }
  63. }
  64. $pageData = $this->_loadPageInfo($langIds);
  65. $langData = $this->_loadLangInfo($langIds);
  66. common::echo_json_encode(200,array("pageData" =>$pageData,"langData" =>$langData));
  67. }
  68. /*
  69. * multilingual_load
  70. */
  71. if ($operate == "multilingual_init") {
  72. $this->_multilingual_init();
  73. }
  74. if ($operate == "multilingual_search") {
  75. $result = $this->_multilingual_search();
  76. common::echo_json_encode(200,$result);
  77. }
  78. /*
  79. * multilingual_save
  80. */
  81. if ($operate == "multilingual_save") {
  82. $multilingual_param = $_POST['multilingual_param'];
  83. $this->_multilingual_save($multilingual_param);
  84. }
  85. /*
  86. * multilingual_save
  87. */
  88. if ($operate == "multilingual_save_all") {
  89. $multilingual_param = $_POST['multilingual_param'];
  90. $this->_multilingual_save_oneself($multilingual_param);
  91. }
  92. if ($operate == "load_all_pages_by_lang") {
  93. $langkey = common::check_input($_POST['langkey']);
  94. $this->_loadAllPagesByLang($langkey);
  95. }
  96. if ($operate == "edi_doc_type"){
  97. $json = common::excuteOneSql("select data from public.kln_i18n_pages_init where id = 3");
  98. $data = json_decode($json,true);
  99. $successCount = 0;
  100. $errorCount = 0;
  101. foreach ($data['data'] as $row) {
  102. try {
  103. $code = isset($row['code']) ? "'" . common::check_input($row['code']) . "'" : "NULL";
  104. $name = isset($row['name']) ? "'" . common::check_input($row['name']) . "'" : "NULL";
  105. $description = isset($row['description']) ? "'" . common::check_input($row['description']) . "'" : "NULL";
  106. $version_policy = isset($row['versionPolicy']) ? "'" . common::check_input($row['versionPolicy']) . "'" : "NULL";
  107. // 处理 "1"/"0" 字符串或数字
  108. $visible_to_customer = isset($row['visibleToCustomer']) ? "'" . common::check_input($row['visibleToCustomer']) . "'" : "NULL";
  109. $can_delete = isset($row['canDelete']) ? "'" . common::check_input($row['canDelete']) . "'" : "NULL";
  110. $to_destination = isset($row['toDestination']) ? intval($row['toDestination']) : "NULL";
  111. $maximum_file_size = isset($row['maximumFileSize']) ? floatval($row['maximumFileSize']) : "NULL";
  112. $supported_suffixes = isset($row['supportedSuffixes']) ? "'" . common::check_input($row['supportedSuffixes']) . "'" : "NULL";
  113. $biz_type = isset($row['bizType']) ? "'" . common::check_input($row['bizType']) . "'" : "NULL";
  114. $shipment_type = isset($row['shipmentType']) ? "'" . common::check_input($row['shipmentType']) . "'" : "NULL";
  115. $field_code = isset($row['fieldCode']) ? "'" . common::check_input($row['fieldCode']) . "'" : "NULL";
  116. $rule_exp = isset($row['ruleExp']) ? "'" . common::check_input($row['ruleExp']) . "'" : "NULL";
  117. $old_code = isset($row['oldCode']) ? "'" . common::check_input($row['oldCode']) . "'" : "NULL";
  118. $old_name = isset($row['oldName']) ? "'" . common::check_input($row['oldName']) . "'" : "NULL";
  119. $biz_cate = isset($row['bizCate']) ? "'" . common::check_input($row['bizCate']) . "'" : "NULL";
  120. $is_old = isset($row['isOld']) ? "'" . common::check_input($row['isOld']) . "'" : "NULL";
  121. $is_business = isset($row['isBusiness']) ? "'" . common::check_input($row['isBusiness']) . "'" : "NULL";
  122. $upload_file_name_rule_suffix = isset($row['uploadFileNameRuleSuffix']) ? "'" . common::check_input($row['uploadFileNameRuleSuffix']) . "'" : "NULL";
  123. $customer_upload = isset($row['customerUpload']) ? "'" . common::check_input($row['customerUpload']) . "'" : "NULL";
  124. // 处理 null 值 (数据库 NULL)
  125. $notify_station = isset($row['notifyStation']) ? "'" . common::check_input($row['notifyStation']) . "'" : "NULL";
  126. $auto_sync_to_station = isset($row['autoSyncToStation']) ? "'" . common::check_input($row['autoSyncToStation']) . "'" : "NULL";
  127. // --- 拼接 SQL 语句 ---
  128. // 注意:表名使用双引号 "document_codes" 以确保大小写敏感(如果表名是小写 codes 可能不需要,但为了保险)
  129. $insertSQL = "INSERT INTO doc_type (
  130. code, name, description, version_policy, visible_to_customer,
  131. can_delete, to_destination, maximum_file_size, supported_suffixes,
  132. biz_type, shipment_type, field_code, rule_exp, old_code,
  133. old_name, biz_cate, is_old, is_business, upload_file_name_rule_suffix,
  134. customer_upload, notify_station, auto_sync_to_station
  135. ) VALUES (
  136. $code, $name, $description, $version_policy, $visible_to_customer,
  137. $can_delete, $to_destination, $maximum_file_size, $supported_suffixes,
  138. $biz_type, $shipment_type, $field_code, $rule_exp, $old_code,
  139. $old_name, $biz_cate, $is_old, $is_business, $upload_file_name_rule_suffix,
  140. $customer_upload, $notify_station, $auto_sync_to_station
  141. )";
  142. common::excuteUpdateSql($insertSQL);
  143. $successCount++;
  144. } catch (PDOException $e) {
  145. echo "插入失败 (Code: {$row['code']}): " . $e->getMessage() . "\n";
  146. $errorCount++;
  147. }
  148. }
  149. echo "数据处理完成。\n成功插入: $successCount 条\n失败: $errorCount 条\n";
  150. }
  151. }
  152. private function _multilingual_init() {
  153. // 1. 获取并解析 JSON 数据
  154. $sql = "select * from public.kln_i18n_pages_init where id = 2";
  155. $data = common::excuteObjectSql($sql);
  156. $rawData = $data['data'];
  157. $rawDataArr = json_decode($rawData, true);
  158. if (!$rawDataArr) {
  159. common::echo_json_encode(500, "Invalid JSON format");
  160. exit();
  161. }
  162. foreach($rawDataArr as $_rawDataArr){
  163. $mode = 'update';
  164. $json = $_rawDataArr;
  165. // 获取控制模式,默认为 'update'
  166. $mode = $mode == 'replace' ? 'replace' : 'update';
  167. $pageKey = isset($json['page']) ? common::check_input($json['page']) : '';
  168. $unverifiedNumber = isset($json['unverifiedNumber']) ? intval($json['unverifiedNumber']) : 0;
  169. $dataList = isset($json['data']) ? $json['data'] : [];
  170. //tracking report booking destinationDelivery
  171. if (empty($pageKey)) {
  172. common::echo_json_encode(500, "Missing page key");
  173. exit();
  174. }
  175. // 2. 定义语言映射配置
  176. $langMap = [
  177. 'traditionalChinese' => ['name' => '繁体中文', 'code' => 'zh-TW'],
  178. 'simplifiedChinese' => ['name' => '简体中文', 'code' => 'zh-CN'],
  179. 'english' => ['name' => '英语', 'code' => 'en-US'],
  180. 'french' => ['name' => '法语', 'code' => 'fr-FR'],
  181. 'spanish' => ['name' => '西班牙语', 'code' => 'es-ES'],
  182. 'portuguese' => ['name' => '葡萄牙语', 'code' => 'pt-BR']
  183. ];
  184. global $db;
  185. $db->StartTrans();
  186. try {
  187. // 第一步:处理页面表 (public.kln_i18n_pages)
  188. $pageId = null;
  189. // --- 模式判断:如果是覆盖模式,先删除旧数据 ---
  190. if ($mode === 'replace') {
  191. // 1. 先删子表 (public.kln_i18n_keys)
  192. $kikSqlDelete = "DELETE FROM public.kln_i18n_keys WHERE page_id IN (SELECT id FROM public.kln_i18n_pages WHERE page_key = '$pageKey')";
  193. $db->Execute($kikSqlDelete) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $kikSqlDelete), 0));
  194. // 2. 再删主表 (public.kln_i18n_pages) - 虽然上面删了子表,这里为了保险或者重置页面信息也可以删,
  195. $delPageSql = "DELETE FROM public.kln_i18n_pages WHERE page_key = '$pageKey'";
  196. $db->Execute($delPageSql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $delPageSql), 0));
  197. }
  198. // --- 查询页面是否存在 ---
  199. $checkPageSql = "SELECT id FROM public.kln_i18n_pages WHERE page_key = '$pageKey'";
  200. $checkPageRes = $db->GetRow($checkPageSql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $checkPageSql), 0));
  201. if (!empty($checkPageRes)) {
  202. // 存在 -> 更新
  203. $pageId = $checkPageRes['id'];
  204. $updatePageSql = "UPDATE public.kln_i18n_pages SET unverified_number = $unverifiedNumber WHERE id = $pageId";
  205. $db->Execute($updatePageSql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $updatePageSql), 0));
  206. } else {
  207. // 不存在 -> 插入
  208. $insertPageSql = "INSERT INTO public.kln_i18n_pages (page_key, unverified_number, description) VALUES ('$pageKey', $unverifiedNumber, '')";
  209. $db->Execute($insertPageSql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $insertPageSql), 0));
  210. // 获取新生成的 ID (PostgreSQL)
  211. $seqSql = "SELECT currval('public.kln_i18n_pages_id_seq')";
  212. $pageIdRow = $db->GetRow($seqSql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $seqSql), 0));
  213. $pageId = $pageIdRow['currval'];
  214. }
  215. // 第二步:循环处理数据
  216. foreach ($dataList as $item) {
  217. $transKey = common::check_input($item['key']);
  218. $originValue = isset($item['originEnglish']) ? common::check_input($item['originEnglish']) : '';
  219. foreach ($langMap as $jsonKey => $langInfo) {
  220. // 只处理 JSON 中存在的数据
  221. if (isset($item[$jsonKey])) {
  222. $transValue = common::check_input($item[$jsonKey]);
  223. $statusKey = common::check_input($jsonKey . 'Status');
  224. $status = isset($item[$statusKey]) ? intval($item[$statusKey]) : 0;
  225. // --- 1. 处理语言表 (public.kln_i18n_languages) ---
  226. $langKey = common::check_input($jsonKey);
  227. $langName = common::check_input($langInfo['name']);
  228. $localeCode = common::check_input($langInfo['code']);
  229. // 查询语言是否存在
  230. $checkLangSql = "SELECT id FROM public.kln_i18n_languages WHERE lang_key = '$langKey'";
  231. $checkLangRes = $db->GetRow($checkLangSql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $checkLangSql), 0));
  232. if (!empty($checkLangRes)) {
  233. // 存在 -> 更新
  234. $langId = $checkLangRes['id'];
  235. $updateLangSql = "UPDATE public.kln_i18n_languages SET lang_name = '$langName', locale_code = '$localeCode' WHERE id = $langId";
  236. $db->Execute($updateLangSql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $updateLangSql), 0));
  237. } else {
  238. // 不存在 -> 插入
  239. $insertLangSql = "INSERT INTO public.kln_i18n_languages (lang_key, lang_name, locale_code, is_active) VALUES ('$langKey', '$langName', '$localeCode', true)";
  240. $db->Execute($insertLangSql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $updateLangSql), 0));
  241. // 获取 ID
  242. $seqLangSql = "SELECT currval('public.kln_i18n_languages_id_seq')";
  243. $langIdRow = $db->GetRow($seqLangSql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $seqLangSql), 0));
  244. $langId = $langIdRow['currval'];
  245. }
  246. // --- 2. 处理词条表 (public.kln_i18n_keys) ---
  247. // 查询词条是否存在
  248. $checkKeySql = "SELECT id FROM public.kln_i18n_keys WHERE page_id = $pageId AND lang_id = $langId AND trans_key = '$transKey'";
  249. $checkKeyRes = $db->GetRow($checkKeySql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $checkKeySql), 0));
  250. if (!empty($checkKeyRes)) {
  251. // 存在 -> 更新
  252. $updateKeySql = "UPDATE public.kln_i18n_keys SET trans_value = '$transValue', orgin_value = '$originValue', status = $status WHERE id = " . $checkKeyRes['id'];
  253. $db->Execute($updateKeySql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $updateKeySql), 0));
  254. } else {
  255. // 不存在 -> 插入
  256. $insertKeySql = "INSERT INTO public.kln_i18n_keys (page_id, lang_id, trans_key, trans_value, orgin_value, status) VALUES ($pageId, $langId, '$transKey', '$transValue', '$originValue', $status)";
  257. $db->Execute($insertKeySql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $insertKeySql), 0));
  258. }
  259. }
  260. }
  261. }
  262. } catch (Exception $e) {
  263. // 捕获异常,标记错误,以便回滚
  264. error_log("Exception in multilingual_init: " . $e->getMessage());
  265. }
  266. // 结束事务
  267. if ($db->CompleteTrans() === FALSE) {
  268. $msg = 'Save Error';
  269. } else {
  270. $msg = 'Save Success';
  271. }
  272. }
  273. common::echo_json_encode(200, $msg);
  274. exit();
  275. }
  276. /**
  277. * 根据传入的 page_key 查询多语言信息并组装成 JSON 格式
  278. * 支持多个页面查询,将所有数据整合到一个 data 数组中
  279. *
  280. * @param string|array $pageKey 页面标识 (例如 'login' 或 ['login', 'register'])
  281. * @return array 返回组装好的数组 (通常最后会 json_encode 输出)
  282. */
  283. public function _multilingual_search() {
  284. $pageKey = $_POST['pagekey'];
  285. $pageIds = [];
  286. // 1. 统一处理 $pageIds 数组
  287. if (empty($pageKey) || strtoupper($pageKey) == "ALL") {
  288. // 如果没传或传 ALL,直接查询所有页面的 ID
  289. $pageSql = "SELECT id FROM public.kln_i18n_pages";
  290. $pageRows = common::excuteListSql($pageSql);
  291. if ($pageRows) {
  292. $pageIds = array_column($pageRows, 'id');
  293. }
  294. } else {
  295. // 2. 如果指定了页面,使用 IN 查询一次性获取
  296. $pages = explode(',', $pageKey);
  297. // 安全过滤:防止 SQL 注入,并确保只处理非空字符串
  298. $safePages = array();
  299. foreach ($pages as $p) {
  300. $p = trim($p);
  301. if (!empty($p)) {
  302. $safePages[] = "'" . common::check_input($p) . "'";
  303. }
  304. }
  305. if (!empty($safePages)) {
  306. $inClause = implode(',', $safePages);
  307. // 优化点:一次查询获取所有匹配的 ID 和 unverified_number
  308. $pageSql = "SELECT id, unverified_number FROM public.kln_i18n_pages WHERE page_key IN ($inClause)";
  309. $pageRows = common::excuteListSql($pageSql);
  310. if ($pageRows) {
  311. $pageIds = array_column($pageRows, 'id');
  312. }
  313. }
  314. }
  315. // 3. 如果没有找到任何页面,返回空数组
  316. if (empty($pageIds)) {
  317. return array();
  318. }
  319. //查询指定语言
  320. $langIds = [];
  321. $langkey = $_POST['langKey'];
  322. // 1. 统一处理 $langs 数组
  323. if (empty($langkey) || strtoupper($langkey) == "ALL") {
  324. // 如果没传或传 ALL,直接查询所有激活语言的 ID
  325. // 优化点:直接查 id,不需要先查 key 再查 id
  326. $langSql = "SELECT id FROM public.kln_i18n_languages";
  327. $langRows = common::excuteListSql($langSql);
  328. if ($langRows) {
  329. $langIds = array_column($langRows, 'id');
  330. }
  331. } else {
  332. // 2. 如果指定了语言,使用 IN 查询一次性获取
  333. $langs = explode(',', $langkey);
  334. // 安全过滤:防止 SQL 注入,并确保只处理非空字符串
  335. $safeLangs = array();
  336. foreach ($langs as $l) {
  337. $l = trim($l);
  338. if (!empty($l)) {
  339. $safeLangs[] = "'" . common::check_input($l) . "'";
  340. }
  341. }
  342. if (!empty($safeLangs)) {
  343. // 拼接 IN 条件:('english', 'french')
  344. $inClause = implode(',', $safeLangs);
  345. $langSql = "SELECT id FROM public.kln_i18n_languages WHERE lang_key IN ($inClause)";
  346. $langRows = common::excuteListSql($langSql);
  347. if ($langRows) {
  348. $langIds = array_column($langRows, 'id');
  349. }
  350. }
  351. }
  352. // 4. 查询所有指定页面的翻译词条(一次查询获取所有数据)
  353. $sql = "SELECT
  354. k.trans_key,
  355. k.trans_value,
  356. k.status,
  357. k.orgin_value,
  358. l.lang_key,
  359. p.page_key AS key_page
  360. FROM public.kln_i18n_keys k
  361. JOIN public.kln_i18n_languages l ON k.lang_id = l.id
  362. JOIN public.kln_i18n_pages p ON k.page_id = p.id
  363. WHERE k.page_id IN (" . implode(',', $pageIds) . ")
  364. AND k.lang_id IN (" . implode(',', $langIds) . ")
  365. ORDER BY k.trans_key, p.page_key";
  366. $rows = common::excuteListSql($sql);
  367. if ($rows === FALSE) {
  368. return array();
  369. }
  370. // 5. 数据重组(核心逻辑)
  371. $dataMap = array();
  372. foreach ($rows as $row) {
  373. $key = $row['trans_key'];
  374. $langKey = $row['lang_key'];
  375. // 如果这个 key 还没初始化,先初始化
  376. $mapKey = $key.':'.$row['key_page'];
  377. //$mapKey = $key;
  378. if (!isset($dataMap[$mapKey])) {
  379. $dataMap[$mapKey] = array(
  380. 'key' => $key,
  381. 'key_page' => $row['key_page'] // 记录所属页面
  382. );
  383. }
  384. // 动态填充语言字段
  385. $dataMap[$mapKey][$langKey] = $row['trans_value'];
  386. // 填充状态字段
  387. $dataMap[$mapKey][$langKey . 'Status'] = intval($row['status']);
  388. // 填充原始值(如果有)
  389. //if (!empty($row['orgin_value'])) {
  390. $dataMap[$mapKey]['originEnglish'] = $row['orgin_value'];
  391. //}
  392. }
  393. // 6. 将 Map 转换为数组列表
  394. $dataList = array_values($dataMap);
  395. // 7. 组装最终结果
  396. $result = array(
  397. 'page' => $pageKey,
  398. 'data' => $dataList
  399. );
  400. //重新查询一下page load
  401. $pageData = $this->_loadPageInfo($langIds);
  402. $result['pageData'] = $pageData;
  403. //langIds传空,意思是查全部语言
  404. $langData = $this->_loadLangInfo(null,$pageIds);
  405. $result['langData'] = $langData;
  406. return $result;
  407. }
  408. /**
  409. * 保存多语言数据
  410. *
  411. * @param array $multilingual_param 页面未审核数量参数,格式:[{unverifiedNumber: 3, page: 'login'}, ...]
  412. * @param array $multilingual_trans_param 翻译状态参数,格式:[{page: 'login', lang: 'traditionalChinese', trans_key: 'username', status: 1}, ...]
  413. * @return bool 是否保存成功
  414. */
  415. public function _multilingual_save($multilingual_param) {
  416. global $db;
  417. try {
  418. // 开启事务确保数据一致性
  419. $db->StartTrans();
  420. //2. 处理翻译词条状态更新
  421. foreach ($multilingual_param as $param) {
  422. $pageKey = common::check_input($param['page']);
  423. $langKey = common::check_input($param['lang']);
  424. $transKey = common::check_input($param['trans_key']);
  425. $trans_value = common::check_input($param['trans_value']);
  426. $status = $param['status'];
  427. // 查询页面ID
  428. $pageSql = "SELECT id FROM public.kln_i18n_pages WHERE page_key = '".$pageKey."'";
  429. $pageId = $db->GetOne($pageSql);
  430. if (!$pageId) {
  431. throw new Exception("Page not found: " . $pageKey);
  432. }
  433. // 查询语言ID
  434. $langSql = "SELECT id FROM public.kln_i18n_languages WHERE lang_key = '".$langKey."'";
  435. $langId = $db->GetOne($langSql);
  436. if (!$langId) {
  437. throw new Exception("Language not found: " . $langKey);
  438. }
  439. // 更新翻译状态
  440. $updateTransSql = "UPDATE public.kln_i18n_keys SET status = $status, trans_value = '$trans_value' ".
  441. " WHERE page_id = " . $pageId .
  442. " AND lang_id = " . $langId .
  443. " AND trans_key = '".$transKey."'";
  444. $db->Execute($updateTransSql);
  445. }
  446. } catch (Exception $e) {
  447. // 捕获异常,标记错误,以便回滚
  448. error_log("Exception in multilingual_save: " . $e->getMessage());
  449. }
  450. // 结束事务
  451. if ($db->CompleteTrans() === FALSE) {
  452. $msg = 'Save Error';
  453. } else {
  454. $msg = 'Save Success';
  455. }
  456. common::echo_json_encode(200, $msg);
  457. exit();
  458. }
  459. /**
  460. * 保存多语言数据 (自己使用,包含跟多字段的编辑和添加)
  461. *
  462. * @param array $multilingual_param 页面未审核数量参数,格式:[{unverifiedNumber: 3, page: 'login'}, ...]
  463. * @param array $multilingual_trans_param 翻译状态参数,格式:[{page: 'login', lang: 'traditionalChinese', trans_key: 'username', status: 1}, ...]
  464. * @return bool 是否保存成功
  465. */
  466. public function _multilingual_save_oneself($multilingual_param) {
  467. global $db;
  468. try {
  469. // 开启事务确保数据一致性
  470. $db->StartTrans();
  471. //2. 处理翻译词条状态更新
  472. foreach ($multilingual_param as $param) {
  473. $pageKey = common::check_input($param['page']);
  474. $langKey = common::check_input($param['lang']);
  475. $transKey = common::check_input($param['trans_key']);
  476. $trans_value = common::check_input($param['trans_value']);
  477. $status = $param['status'];
  478. // 查询页面ID
  479. $pageSql = "SELECT id FROM public.kln_i18n_pages WHERE page_key = '".$pageKey."'";
  480. $pageId = $db->GetOne($pageSql);
  481. if (!$pageId) {
  482. throw new Exception("Page not found: " . $pageKey);
  483. }
  484. // 查询语言ID
  485. $langSql = "SELECT id FROM public.kln_i18n_languages WHERE lang_key = '".$langKey."'";
  486. $langId = $db->GetOne($langSql);
  487. if (!$langId) {
  488. throw new Exception("Language not found: " . $langKey);
  489. }
  490. if( $langId == 'originEnglish'){
  491. $ii8_Sql = "SELECT id FROM public.kln_i18n_keys WHERE page_id = " . $pageId . " AND trans_key = '".$transKey."'";
  492. $ii8 = $db->GetOne($ii8_Sql);
  493. if (!$ii8) {
  494. $langAllSql = "SELECT id FROM public.kln_i18n_languages";
  495. $langAllId = $db->GetAll($langAllSql);
  496. foreach($langAllId as $_langAllId){
  497. // 不存在 -> 插入
  498. $insertKeySql = "INSERT INTO public.kln_i18n_keys (page_id, lang_id, trans_key, trans_value, status)
  499. VALUES ($pageId, ".$_langAllId['id'].", '$transKey', '$trans_value', 0)";
  500. $db->Execute($insertKeySql);
  501. }
  502. }else{
  503. // 更新翻译状态
  504. $updateTransSql = "UPDATE public.kln_i18n_keys SET status = 0, orgin_value = '$trans_value' ".
  505. " WHERE page_id = " . $pageId .
  506. " AND trans_key = '".$transKey."'";
  507. $db->Execute($updateTransSql);
  508. }
  509. } else {
  510. $ii8_Sql = "SELECT id FROM public.kln_i18n_keys WHERE page_id = " . $pageId . " AND lang_id = ".$langId." AND trans_key = '".$transKey."'";
  511. $ii8 = $db->GetOne($ii8_Sql);
  512. if (!$ii8) {
  513. // 不存在 -> 插入
  514. $insertKeySql = "INSERT INTO public.kln_i18n_keys (page_id, lang_id, trans_key, trans_value, status)
  515. VALUES ($pageId, $langId, '$transKey', '$trans_value', $status)";
  516. $db->Execute($insertKeySql);
  517. }else{
  518. // 更新翻译状态
  519. $updateTransSql = "UPDATE public.kln_i18n_keys SET status = $status, trans_value = '$trans_value' ".
  520. " WHERE page_id = " . $pageId .
  521. " AND lang_id = " . $langId .
  522. " AND trans_key = '".$transKey."'";
  523. $db->Execute($updateTransSql);
  524. }
  525. }
  526. }
  527. } catch (Exception $e) {
  528. // 捕获异常,标记错误,以便回滚
  529. error_log("Exception in multilingual_save: " . $e->getMessage());
  530. }
  531. // 结束事务
  532. if ($db->CompleteTrans() === FALSE) {
  533. $msg = 'Save Error';
  534. } else {
  535. $msg = 'Save Success';
  536. }
  537. common::echo_json_encode(200, $msg);
  538. exit();
  539. }
  540. /**
  541. * load page info
  542. */
  543. public function _loadPageInfo($langIds){
  544. $pageSql = "SELECT
  545. (select page_key from public.kln_i18n_pages where id = page_id) as page_key,
  546. COUNT(*) AS unverified_count
  547. FROM (
  548. SELECT
  549. page_id,
  550. trans_key,
  551. BOOL_OR(status = 0) AS all_unverified
  552. FROM public.kln_i18n_keys
  553. WHERE lang_id IN (" . implode(',', $langIds) . ")
  554. GROUP BY page_id, trans_key
  555. ) AS subquery
  556. WHERE all_unverified = TRUE GROUP BY page_id;";
  557. $pageData = common::excuteListSql($pageSql);
  558. $unverified_count = 0;
  559. foreach($pageData as $_pageData){
  560. $unverified_count += $_pageData['unverified_count'];
  561. }
  562. $newItem = [
  563. 'page_key' => 'all',
  564. 'unverified_count' =>$unverified_count
  565. ];
  566. // 将新数组插入到 $pageDate 的开头
  567. array_unshift($pageData, $newItem);
  568. return $pageData;
  569. }
  570. /**
  571. * load lang info
  572. */
  573. public function _loadLangInfo($langIds,$pageIds = array()){
  574. $page_id_sql = "";
  575. if(!empty($pageIds)){
  576. $page_id_sql = "AND k.page_id IN (" . implode(',', $pageIds) . ")";
  577. }
  578. $lang_id_sql = "";
  579. if(!empty($langIds)){
  580. $lang_id_sql = "AND l.id IN (" . implode(',', $langIds) . ")";
  581. }
  582. $langSql = "SELECT
  583. l.lang_key,
  584. COUNT(k.id) AS unverified_count
  585. FROM public.kln_i18n_languages l
  586. LEFT JOIN public.kln_i18n_keys k ON l.id = k.lang_id
  587. $page_id_sql
  588. AND k.status = 0
  589. WHERE
  590. l.is_active = TRUE
  591. $lang_id_sql
  592. GROUP BY
  593. l.id, l.lang_key, l.lang_name;";
  594. $langData = common::excuteListSql($langSql);
  595. $unverified_count = 0;
  596. $retLangData = array('all'=>0);
  597. foreach($langData as $_langData){
  598. $unverified_count += $_langData['unverified_count'];
  599. $retLangData[$_langData['lang_key']] = intval($_langData['unverified_count']);
  600. }
  601. $retLangData['all'] =$unverified_count;
  602. return $retLangData;
  603. }
  604. /**
  605. * 按照指定语言查询所有页面的多语言信息,并输出标准 JSON 格式
  606. * 兼容 PHP 7.4
  607. *
  608. * @param string $langKey 语言键,例如 'english', 'simplifiedChinese'
  609. * @return void 输出 JSON 并终止脚本
  610. */
  611. public function _loadAllPagesByLang($langKey = 'english') {
  612. // 1. 参数校验与安全过滤
  613. $langKey = common::check_input($langKey);
  614. if (empty($langKey)) {
  615. $langKey = 'english'; // 默认回退到英语
  616. }
  617. try {
  618. // 2. 查询指定语言的 ID
  619. $langSql = "SELECT id FROM public.kln_i18n_languages WHERE lang_key = ? AND is_active = TRUE limit 1";
  620. $langObj = common::excuteObjectPrepareSql($langSql,array($langKey));
  621. if (empty($langObj)) {
  622. common::echo_json_encode(500, "Invalid languages");
  623. exit();
  624. }
  625. $langId = $langObj['id'];
  626. // 3. 查询所有激活的页面
  627. $pageSql = "SELECT id, page_key FROM public.kln_i18n_pages WHERE 1=1";
  628. $pageRows = common::excuteListSql($pageSql);
  629. // 4. 构建页面 ID 列表,用于后续查询
  630. $pageIdMap = array();
  631. foreach ($pageRows as $row) {
  632. $pageIdMap[$row['id']] = $row['page_key'];
  633. }
  634. $pageIds = array_keys($pageIdMap);
  635. // 5. 查询该语言下所有页面的所有翻译词条
  636. $inClause = implode(',', $pageIds);
  637. $transSql = "SELECT page_id, trans_key, trans_value
  638. FROM public.kln_i18n_keys
  639. WHERE lang_id = $langId
  640. AND page_id IN ($inClause)";
  641. $transRows = common::excuteListSql($transSql);
  642. // 6. 数据组装 (核心逻辑)
  643. $result = array();
  644. // 先初始化所有页面的空数组
  645. foreach ($pageIdMap as $pageKey) {
  646. $result[$pageKey] = array();
  647. }
  648. // 填充翻译数据
  649. foreach ($transRows as $row) {
  650. $pageKey = $pageIdMap[$row['page_id']];
  651. $transKey = $row['trans_key'];
  652. $transValue = $row['trans_value'];
  653. // 直接赋值: $result['login']['username'] = 'User Name'
  654. $result[$pageKey][$transKey] = $transValue;
  655. }
  656. // 7. 输出 JSON
  657. common::echo_json_encode(200, $result);
  658. exit();
  659. } catch (Exception $e) {
  660. // 错误处理
  661. error_log("Error in loadAllPagesByLang: " . $e->getMessage());
  662. common::echo_json_encode(500, "Invalid languages");
  663. exit();
  664. }
  665. }
  666. }
  667. ?>