| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602 |
- <?php
- if (!defined('IN_ONLINE')) {
- exit('Access Denied');
- }
- /**
- * Description of multilingual
- *
- * @author Administrator
- */
- class multilingual{
- private static $_multilingual;
- function __construct() {
-
- }
- public static function getInstance() {
- global $memory_limit;
- $memory_limit = ini_get("memory_limit");
- ini_set("memory_limit", '2048M');
- if (!self::$_multilingual) {
- $c = __CLASS__;
- self::$_multilingual = new $c;
- }
- return self::$_multilingual;
- }
- public function multilingual_config() {
- $operate = utils::_get('operate');
- $operate = strtolower($operate);
- /*
- * multilingual_page_load
- */
- if ($operate == "multilingual_page") {
- //查询指定语言
- $langIds = [];
- $langkey = $_POST['langkey'];
- // 1. 统一处理 $langs 数组
- if (empty($langkey) || strtoupper($langkey) == "ALL") {
- // 如果没传或传 ALL,直接查询所有激活语言的 ID
- // 优化点:直接查 id,不需要先查 key 再查 id
- $langSql = "SELECT id FROM kln_i18n_languages";
- $langRows = common::excuteListSql($langSql);
- if ($langRows) {
- $langIds = array_column($langRows, 'id');
- }
- } else {
- // 2. 如果指定了语言,使用 IN 查询一次性获取
- $langs = explode(',', $langkey);
- // 安全过滤:防止 SQL 注入,并确保只处理非空字符串
- $safeLangs = array();
- foreach ($langs as $l) {
- $l = trim($l);
- if (!empty($l)) {
- $safeLangs[] = "'" . common::check_input($l) . "'";
- }
- }
- if (!empty($safeLangs)) {
- // 拼接 IN 条件:('english', 'french')
- $inClause = implode(',', $safeLangs);
- $langSql = "SELECT id FROM kln_i18n_languages WHERE lang_key IN ($inClause)";
- $langRows = common::excuteListSql($langSql);
- if ($langRows) {
- $langIds = array_column($langRows, 'id');
- }
- }
- }
- $pageData = $this->_loadPageInfo($langIds);
- $langData = $this->_loadLangInfo($langIds);
- common::echo_json_encode(200,array("pageData" =>$pageData,"langData" =>$langData));
- }
- /*
- * multilingual_load
- */
- if ($operate == "multilingual_init") {
- $this->_multilingual_init();
- }
- if ($operate == "multilingual_search") {
- $result = $this->_multilingual_search();
- common::echo_json_encode(200,$result);
- }
- /*
- * multilingual_save
- */
- if ($operate == "multilingual_save") {
- $multilingual_param = $_POST['multilingual_param'];
- $this->_multilingual_save($multilingual_param);
- }
- if ($operate == "load_all_pages_by_lang") {
- $langkey = common::check_input($_POST['langkey']);
- $this->_loadAllPagesByLang($langkey);
- }
- }
- private function _multilingual_init() {
- // 1. 获取并解析 JSON 数据
- $sql = "select * from public.kln_i18n_pages_init where id = 2";
- $data = common::excuteObjectSql($sql);
- $rawData = $data['data'];
- $rawDataArr = json_decode($rawData, true);
- if (!$rawDataArr) {
- common::echo_json_encode(500, "Invalid JSON format");
- exit();
- }
- foreach($rawDataArr as $_rawDataArr){
- $mode = 'update';
- $json = $_rawDataArr;
- // 获取控制模式,默认为 'update'
- $mode = $mode == 'replace' ? 'replace' : 'update';
- $pageKey = isset($json['page']) ? common::check_input($json['page']) : '';
- $unverifiedNumber = isset($json['unverifiedNumber']) ? intval($json['unverifiedNumber']) : 0;
- $dataList = isset($json['data']) ? $json['data'] : [];
- //tracking report booking destinationDelivery
- if (empty($pageKey)) {
- common::echo_json_encode(500, "Missing page key");
- exit();
- }
- // 2. 定义语言映射配置
- $langMap = [
- 'traditionalChinese' => ['name' => '繁体中文', 'code' => 'zh-TW'],
- 'simplifiedChinese' => ['name' => '简体中文', 'code' => 'zh-CN'],
- 'english' => ['name' => '英语', 'code' => 'en-US'],
- 'french' => ['name' => '法语', 'code' => 'fr-FR'],
- 'spanish' => ['name' => '西班牙语', 'code' => 'es-ES'],
- 'portuguese' => ['name' => '葡萄牙语', 'code' => 'pt-BR']
- ];
- global $db;
- $db->StartTrans();
- try {
- // 第一步:处理页面表 (kln_i18n_pages)
- $pageId = null;
- // --- 模式判断:如果是覆盖模式,先删除旧数据 ---
- if ($mode === 'replace') {
- // 1. 先删子表 (kln_i18n_keys)
- $kikSqlDelete = "DELETE FROM kln_i18n_keys WHERE page_id IN (SELECT id FROM kln_i18n_pages WHERE page_key = '$pageKey')";
- $db->Execute($kikSqlDelete) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $kikSqlDelete), 0));
- // 2. 再删主表 (kln_i18n_pages) - 虽然上面删了子表,这里为了保险或者重置页面信息也可以删,
- $delPageSql = "DELETE FROM kln_i18n_pages WHERE page_key = '$pageKey'";
- $db->Execute($delPageSql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $delPageSql), 0));
- }
- // --- 查询页面是否存在 ---
- $checkPageSql = "SELECT id FROM kln_i18n_pages WHERE page_key = '$pageKey'";
- $checkPageRes = $db->GetRow($checkPageSql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $checkPageSql), 0));
-
- if (!empty($checkPageRes)) {
- // 存在 -> 更新
- $pageId = $checkPageRes['id'];
- $updatePageSql = "UPDATE kln_i18n_pages SET unverified_number = $unverifiedNumber WHERE id = $pageId";
- $db->Execute($updatePageSql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $updatePageSql), 0));
- } else {
- // 不存在 -> 插入
- $insertPageSql = "INSERT INTO kln_i18n_pages (page_key, unverified_number, description) VALUES ('$pageKey', $unverifiedNumber, '')";
- $db->Execute($insertPageSql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $insertPageSql), 0));
-
- // 获取新生成的 ID (PostgreSQL)
- $seqSql = "SELECT currval('kln_i18n_pages_id_seq')";
- $pageIdRow = $db->GetRow($seqSql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $seqSql), 0));
- $pageId = $pageIdRow['currval'];
- }
- // 第二步:循环处理数据
- foreach ($dataList as $item) {
- $transKey = common::check_input($item['key']);
- $originValue = isset($item['originEnglish']) ? common::check_input($item['originEnglish']) : '';
- foreach ($langMap as $jsonKey => $langInfo) {
- // 只处理 JSON 中存在的数据
- if (isset($item[$jsonKey])) {
- $transValue = common::check_input($item[$jsonKey]);
- $statusKey = common::check_input($jsonKey . 'Status');
- $status = isset($item[$statusKey]) ? intval($item[$statusKey]) : 0;
- // --- 1. 处理语言表 (kln_i18n_languages) ---
- $langKey = common::check_input($jsonKey);
- $langName = common::check_input($langInfo['name']);
- $localeCode = common::check_input($langInfo['code']);
- // 查询语言是否存在
- $checkLangSql = "SELECT id FROM kln_i18n_languages WHERE lang_key = '$langKey'";
- $checkLangRes = $db->GetRow($checkLangSql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $checkLangSql), 0));
- if (!empty($checkLangRes)) {
- // 存在 -> 更新
- $langId = $checkLangRes['id'];
- $updateLangSql = "UPDATE kln_i18n_languages SET lang_name = '$langName', locale_code = '$localeCode' WHERE id = $langId";
- $db->Execute($updateLangSql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $updateLangSql), 0));
- } else {
- // 不存在 -> 插入
- $insertLangSql = "INSERT INTO kln_i18n_languages (lang_key, lang_name, locale_code, is_active) VALUES ('$langKey', '$langName', '$localeCode', true)";
- $db->Execute($insertLangSql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $updateLangSql), 0));
-
- // 获取 ID
- $seqLangSql = "SELECT currval('kln_i18n_languages_id_seq')";
- $langIdRow = $db->GetRow($seqLangSql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $seqLangSql), 0));
- $langId = $langIdRow['currval'];
- }
- // --- 2. 处理词条表 (kln_i18n_keys) ---
- // 查询词条是否存在
- $checkKeySql = "SELECT id FROM kln_i18n_keys WHERE page_id = $pageId AND lang_id = $langId AND trans_key = '$transKey'";
- $checkKeyRes = $db->GetRow($checkKeySql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $checkKeySql), 0));
- if (!empty($checkKeyRes)) {
- // 存在 -> 更新
- $updateKeySql = "UPDATE kln_i18n_keys SET trans_value = '$transValue', orgin_value = '$originValue', status = $status WHERE id = " . $checkKeyRes['id'];
- $db->Execute($updateKeySql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $updateKeySql), 0));
- } else {
- // 不存在 -> 插入
- $insertKeySql = "INSERT INTO kln_i18n_keys (page_id, lang_id, trans_key, trans_value, orgin_value, status) VALUES ($pageId, $langId, '$transKey', '$transValue', '$originValue', $status)";
- $db->Execute($insertKeySql) or ( (!$db->ErrorMsg()) or error_log(common::dbLog($db, $insertKeySql), 0));
- }
- }
- }
- }
- } catch (Exception $e) {
- // 捕获异常,标记错误,以便回滚
- error_log("Exception in multilingual_init: " . $e->getMessage());
- }
- // 结束事务
- if ($db->CompleteTrans() === FALSE) {
- $msg = 'Save Error';
- } else {
- $msg = 'Save Success';
- }
- }
- common::echo_json_encode(200, $msg);
- exit();
- }
-
- /**
- * 根据传入的 page_key 查询多语言信息并组装成 JSON 格式
- * 支持多个页面查询,将所有数据整合到一个 data 数组中
- *
- * @param string|array $pageKey 页面标识 (例如 'login' 或 ['login', 'register'])
- * @return array 返回组装好的数组 (通常最后会 json_encode 输出)
- */
- public function _multilingual_search() {
- $pageKey = $_POST['pagekey'];
- $pageIds = [];
- // 1. 统一处理 $pageIds 数组
- if (empty($pageKey) || strtoupper($pageKey) == "ALL") {
- // 如果没传或传 ALL,直接查询所有页面的 ID
- $pageSql = "SELECT id FROM kln_i18n_pages";
- $pageRows = common::excuteListSql($pageSql);
-
- if ($pageRows) {
- $pageIds = array_column($pageRows, 'id');
- }
- } else {
- // 2. 如果指定了页面,使用 IN 查询一次性获取
- $pages = explode(',', $pageKey);
- // 安全过滤:防止 SQL 注入,并确保只处理非空字符串
- $safePages = array();
- foreach ($pages as $p) {
- $p = trim($p);
- if (!empty($p)) {
- $safePages[] = "'" . common::check_input($p) . "'";
- }
- }
- if (!empty($safePages)) {
- $inClause = implode(',', $safePages);
- // 优化点:一次查询获取所有匹配的 ID 和 unverified_number
- $pageSql = "SELECT id, unverified_number FROM kln_i18n_pages WHERE page_key IN ($inClause)";
- $pageRows = common::excuteListSql($pageSql);
-
- if ($pageRows) {
- $pageIds = array_column($pageRows, 'id');
- }
- }
- }
- // 3. 如果没有找到任何页面,返回空数组
- if (empty($pageIds)) {
- return array();
- }
- //查询指定语言
- $langIds = [];
- $langkey = $_POST['langKey'];
- // 1. 统一处理 $langs 数组
- if (empty($langkey) || strtoupper($langkey) == "ALL") {
- // 如果没传或传 ALL,直接查询所有激活语言的 ID
- // 优化点:直接查 id,不需要先查 key 再查 id
- $langSql = "SELECT id FROM kln_i18n_languages";
- $langRows = common::excuteListSql($langSql);
-
- if ($langRows) {
- $langIds = array_column($langRows, 'id');
- }
- } else {
- // 2. 如果指定了语言,使用 IN 查询一次性获取
- $langs = explode(',', $langkey);
- // 安全过滤:防止 SQL 注入,并确保只处理非空字符串
- $safeLangs = array();
- foreach ($langs as $l) {
- $l = trim($l);
- if (!empty($l)) {
- $safeLangs[] = "'" . common::check_input($l) . "'";
- }
- }
- if (!empty($safeLangs)) {
- // 拼接 IN 条件:('english', 'french')
- $inClause = implode(',', $safeLangs);
- $langSql = "SELECT id FROM kln_i18n_languages WHERE lang_key IN ($inClause)";
- $langRows = common::excuteListSql($langSql);
- if ($langRows) {
- $langIds = array_column($langRows, 'id');
- }
- }
- }
- // 4. 查询所有指定页面的翻译词条(一次查询获取所有数据)
- $sql = "SELECT
- k.trans_key,
- k.trans_value,
- k.status,
- k.orgin_value,
- l.lang_key,
- p.page_key AS key_page
- FROM kln_i18n_keys k
- JOIN kln_i18n_languages l ON k.lang_id = l.id
- JOIN kln_i18n_pages p ON k.page_id = p.id
- WHERE k.page_id IN (" . implode(',', $pageIds) . ")
- AND k.lang_id IN (" . implode(',', $langIds) . ")
- ORDER BY k.trans_key, p.page_key";
-
- $rows = common::excuteListSql($sql);
-
- if ($rows === FALSE) {
- return array();
- }
-
- // 5. 数据重组(核心逻辑)
- $dataMap = array();
-
- foreach ($rows as $row) {
- $key = $row['trans_key'];
- $langKey = $row['lang_key'];
-
- // 如果这个 key 还没初始化,先初始化
- $mapKey = $key.':'.$row['key_page'];
- //$mapKey = $key;
- if (!isset($dataMap[$mapKey])) {
- $dataMap[$mapKey] = array(
- 'key' => $key,
- 'key_page' => $row['key_page'] // 记录所属页面
- );
- }
-
- // 动态填充语言字段
- $dataMap[$mapKey][$langKey] = $row['trans_value'];
-
- // 填充状态字段
- $dataMap[$mapKey][$langKey . 'Status'] = intval($row['status']);
-
- // 填充原始值(如果有)
- //if (!empty($row['orgin_value'])) {
- $dataMap[$mapKey]['orginEnglish'] = $row['orgin_value'];
- //}
- }
-
- // 6. 将 Map 转换为数组列表
- $dataList = array_values($dataMap);
-
- // 7. 组装最终结果
- $result = array(
- 'page' => $pageKey,
- 'data' => $dataList
- );
- //重新查询一下page load
- $pageData = $this->_loadPageInfo($langIds);
- $result['pageData'] = $pageData;
- //langIds传空,意思是查全部语言
- $langData = $this->_loadLangInfo(null,$pageIds);
- $result['langData'] = $langData;
- return $result;
- }
- /**
- * 保存多语言数据
- *
- * @param array $multilingual_param 页面未审核数量参数,格式:[{unverifiedNumber: 3, page: 'login'}, ...]
- * @param array $multilingual_trans_param 翻译状态参数,格式:[{page: 'login', lang: 'traditionalChinese', trans_key: 'username', status: 1}, ...]
- * @return bool 是否保存成功
- */
- public function _multilingual_save($multilingual_param) {
- global $db;
- try {
- // 开启事务确保数据一致性
- $db->StartTrans();
- //2. 处理翻译词条状态更新
- foreach ($multilingual_param as $param) {
- $pageKey = common::check_input($param['page']);
- $langKey = common::check_input($param['lang']);
- $transKey = common::check_input($param['trans_key']);
- $trans_value = common::check_input($param['trans_value']);
- $status = $param['status'];
-
- // 查询页面ID
- $pageSql = "SELECT id FROM kln_i18n_pages WHERE page_key = '".$pageKey."'";
- $pageId = $db->GetOne($pageSql);
- if (!$pageId) {
- throw new Exception("Page not found: " . $pageKey);
- }
-
- // 查询语言ID
- $langSql = "SELECT id FROM kln_i18n_languages WHERE lang_key = '".$langKey."'";
- $langId = $db->GetOne($langSql);
- if (!$langId) {
- throw new Exception("Language not found: " . $langKey);
- }
- // 更新翻译状态
- $updateTransSql = "UPDATE kln_i18n_keys SET status = $status, trans_value = '$trans_value' ".
- " WHERE page_id = " . $pageId .
- " AND lang_id = " . $langId .
- " AND trans_key = '".$transKey."'";
- $db->Execute($updateTransSql);
- }
- } catch (Exception $e) {
- // 捕获异常,标记错误,以便回滚
- error_log("Exception in multilingual_save: " . $e->getMessage());
- }
- // 结束事务
- if ($db->CompleteTrans() === FALSE) {
- $msg = 'Save Error';
- } else {
- $msg = 'Save Success';
- }
- common::echo_json_encode(200, $msg);
- exit();
- }
- /**
- * load page info
- */
- public function _loadPageInfo($langIds){
- $pageSql = "SELECT
- (select page_key from public.kln_i18n_pages where id = page_id) as page_key,
- COUNT(*) AS unverified_count
- FROM (
- SELECT
- page_id,
- trans_key,
- BOOL_OR(status = 0) AS all_unverified
- FROM kln_i18n_keys
- WHERE lang_id IN (" . implode(',', $langIds) . ")
- GROUP BY page_id, trans_key
- ) AS subquery
- WHERE all_unverified = TRUE GROUP BY page_id;";
- $pageData = common::excuteListSql($pageSql);
- $unverified_count = 0;
- foreach($pageData as $_pageData){
- $unverified_count += $_pageData['unverified_count'];
- }
- $newItem = [
- 'page_key' => 'all',
- 'unverified_count' =>$unverified_count
- ];
- // 将新数组插入到 $pageDate 的开头
- array_unshift($pageData, $newItem);
- return $pageData;
- }
- /**
- * load lang info
- */
- public function _loadLangInfo($langIds,$pageIds = array()){
- $page_id_sql = "";
- if(!empty($pageIds)){
- $page_id_sql = "AND k.page_id IN (" . implode(',', $pageIds) . ")";
- }
- $lang_id_sql = "";
- if(!empty($langIds)){
- $lang_id_sql = "AND l.id IN (" . implode(',', $langIds) . ")";
- }
- $langSql = "SELECT
- l.lang_key,
- COUNT(k.id) AS unverified_count
- FROM kln_i18n_languages l
- LEFT JOIN kln_i18n_keys k ON l.id = k.lang_id
- $page_id_sql
- AND k.status = 0
- WHERE
- l.is_active = TRUE
- $lang_id_sql
- GROUP BY
- l.id, l.lang_key, l.lang_name;";
- $langData = common::excuteListSql($langSql);
- $unverified_count = 0;
- $retLangData = array('all'=>0);
- foreach($langData as $_langData){
- $unverified_count += $_langData['unverified_count'];
- $retLangData[$_langData['lang_key']] = intval($_langData['unverified_count']);
- }
- $retLangData['all'] =$unverified_count;
- return $retLangData;
- }
- /**
- * 按照指定语言查询所有页面的多语言信息,并输出标准 JSON 格式
- * 兼容 PHP 7.4
- *
- * @param string $langKey 语言键,例如 'english', 'simplifiedChinese'
- * @return void 输出 JSON 并终止脚本
- */
- public function _loadAllPagesByLang($langKey = 'english') {
- // 1. 参数校验与安全过滤
- $langKey = common::check_input($langKey);
- if (empty($langKey)) {
- $langKey = 'english'; // 默认回退到英语
- }
- try {
- // 2. 查询指定语言的 ID
- $langSql = "SELECT id FROM kln_i18n_languages WHERE lang_key = ? AND is_active = TRUE limit 1";
- $langObj = common::excuteObjectPrepareSql($langSql,array($langKey));
-
- if (empty($langObj)) {
- common::echo_json_encode(500, "Invalid languages");
- exit();
- }
- $langId = $langObj['id'];
- // 3. 查询所有激活的页面
- $pageSql = "SELECT id, page_key FROM kln_i18n_pages WHERE 1=1";
- $pageRows = common::excuteListSql($pageSql);
-
- // 4. 构建页面 ID 列表,用于后续查询
- $pageIdMap = array();
- foreach ($pageRows as $row) {
- $pageIdMap[$row['id']] = $row['page_key'];
- }
- $pageIds = array_keys($pageIdMap);
- // 5. 查询该语言下所有页面的所有翻译词条
- $inClause = implode(',', $pageIds);
- $transSql = "SELECT page_id, trans_key, trans_value
- FROM kln_i18n_keys
- WHERE lang_id = $langId
- AND page_id IN ($inClause)";
-
- $transRows = common::excuteListSql($transSql);
- // 6. 数据组装 (核心逻辑)
- $result = array();
-
- // 先初始化所有页面的空数组
- foreach ($pageIdMap as $pageKey) {
- $result[$pageKey] = array();
- }
-
- // 填充翻译数据
- foreach ($transRows as $row) {
- $pageKey = $pageIdMap[$row['page_id']];
- $transKey = $row['trans_key'];
- $transValue = $row['trans_value'];
-
- // 直接赋值: $result['login']['username'] = 'User Name'
- $result[$pageKey][$transKey] = $transValue;
- }
- // 7. 输出 JSON
- common::echo_json_encode(200, $result);
- exit();
- } catch (Exception $e) {
- // 错误处理
- error_log("Error in loadAllPagesByLang: " . $e->getMessage());
- common::echo_json_encode(500, "Invalid languages");
- exit();
- }
- }
- }
- ?>
|