//////////////////////////////////////////////////////////////////////////////////////// //Page 전역 변수 //////////////////////////////////////////////////////////////////////////////////////// var referenceLanguagePack = { language: null, languagePack: {} }; var selectedLanguageCode; var isChanged = false; var changedLang = new Set(); var langPacksColumnList = {}; var pairCounter = 0; var isValidCheck = { modal: false, gc: false }; var dynamicPairContainer; //////////////////////////////////////////////////////////////////////////////////////// //Document Ready //////////////////////////////////////////////////////////////////////////////////////// function execDocReady() { var pluginGroups = [ [ "../reference/light-blue/lib/vendor/jquery.ui.widget.js", "../reference/lightblue4/docs/lib/widgster/widgster.js", "../reference/lightblue4/docs/lib/slimScroll/jquery.slimscroll.min.js", // JS tree "../reference/jquery-plugins/jstree-v.pre1.0/_lib/jquery.cookie.js", "../reference/jquery-plugins/jstree-v.pre1.0/_lib/jquery.hotkeys.js", "../reference/jquery-plugins/jstree-v.pre1.0/jquery.jstree.js", "../reference/light-blue/lib/jquery.iframe-transport.js", "../reference/light-blue/lib/jquery.fileupload.js", "../reference/light-blue/lib/jquery.fileupload-fp.js", "../reference/light-blue/lib/jquery.fileupload-ui.js" ], [ // excel component "../reference/jquery-plugins/jspreadsheet-ce-4.13.1/dist/jsuites.js", "../reference/jquery-plugins/jspreadsheet-ce-4.13.1/dist/index.js", "../reference/jquery-plugins/jspreadsheet-ce-4.13.1/dist/jsuites.css", "../reference/jquery-plugins/jspreadsheet-ce-4.13.1/dist/jspreadsheet.css", "../reference/jquery-plugins/jspreadsheet-ce-4.13.1/dist/jspreadsheet.datatables.css", "../reference/jquery-plugins/jspreadsheet-ce-4.13.1/dist/jspreadsheet.theme.css", "./js/common/jspreadsheet/spreadsheet.js" ] // 추가적인 플러그인 그룹들을 이곳에 추가하면 됩니다. ]; loadPluginGroupsParallelAndSequential(pluginGroups) .then(function () { console.log("모든 플러그인 로드 완료"); dynamicPairContainer = $("#languagePackForm_add_key fieldset"); // 사이드 메뉴 색상 설정 $(".widget").widgster(); setSideMenu("sidebar_menu_config", "sidebar_menu_config_language"); $("#language_pack_list").trigger("create.language_pack_list"); btnClickEvent(); // 전체 언어팩 로드 getAllContents(); }) .catch(function (error) { console.error("플러그인 로드 중 오류 발생"); console.log(error); }); } ///////////////////////////////////////////////// // 엑셀 그리기 ///////////////////////////////////////////////// var SpreadsheetFunctions = (function () { let targetId = { v: "", jq: "" }; let targetRect = { width: 0, height: 0 }; let excelData; // 엑셀 데이터 let excelColumns; // 엑셀 컬럼 let customOptions; // 엑셀 커스텀 옵션들 :: 정의 안할 경우 default let isEditingCell = false; var setDefaultTargetRect = function () { let defaultWidth = $(getTargetId("jq")).width(); let defaultHeight = $(getTargetId("jq")).height(); setTargetRect(defaultWidth, defaultHeight); }; var setTargetRect = function (width, height) { targetRect.width = width; targetRect.height = height; }; var getTargetRect = function (type) { if (type === "width") { return targetRect.width; } else if (type === "height") { return targetRect.height; } else { return targetRect; } }; var setTargetId = function (target) { targetId.v = target; targetId.jq = "#" + target; }; var getTargetId = function (type) { if (type === "jq") { return targetId.jq; } else { return targetId.v; } }; var setExcelData = function (data) { excelData = data; }; var getExcelData = function () { return excelData; }; var updateDataAtIndex = function (index, changedData) { if (excelData) { excelData[index] = changedData; } else { console.log("updateDataAtIndex :: excelData 가 없습니다."); return false; } }; var getDataAtIndex = function (index) { if (excelData) { return excelData[index]; } else { console.log("getDataAtIndex :: excelData 가 없습니다."); return false; } }; var setColumns = function (columns) { excelColumns = columns; }; var getColumns = function () { return excelColumns; }; var setColumnWidth = function (width) { if (excelColumns) { excelColumns = excelColumns.map((column) => ({ ...column, width: width * column.wRatio - 1 })); } }; function setColumnWidthAsync(width) { return new Promise((resolve) => { if (excelColumns) { excelColumns = excelColumns.map((column) => ({ ...column, width: width * column.wRatio - 1 })); } resolve(); // 컬럼 너비 설정이 완료된 후 resolve 호출 }); } var setOptions = function (options) { customOptions = options; }; var getOptions = function () { return customOptions ? customOptions : null; }; var resizeObserver = new ResizeObserver(function (entries) { if (isEditingCell) { // 수정중에는 resize 비활성화 return; } for (let entry of entries) { setTargetRect(entry.contentRect.width, entry.contentRect.height); handleResize(entry.target.id, getTargetRect("width"), getTargetRect("height")); } }); // 모달요소 크기 변화 관찰(Observer) function startObserver() { resizeObserver.observe($(getTargetId("jq"))[0]); } // Observer 멈추기 function stopObserver() { console.log("Stopping ResizeObserver"); resizeObserver.disconnect(); // 크기 변화를 더 이상 감지하지 않음 } function handleResize(id, width, height) { if (id === getTargetId() && height !== 0) { if (excelData) { drawResizedExcel(getTargetId()); } else { console.log("Spreadsheet.handleResize :: 엑셀 데이터 없음"); } } else { console.log("Spreadsheet.handleResize :: id 불일치 또는 height 가 0 입니다."); } } function drawResizedExcel(target) { let $targetId = "#" + target; if ($($targetId).length > 0 && $($targetId)[0].jexcel) { $($targetId)[0].jexcel.destroy(); } setColumnWidthAsync(getTargetRect("width") - 50).then(() => { $($targetId).spreadsheet( $.extend( {}, { columns: getColumns(), data: getExcelData() }, getOptions() ) ); let jexcel_content_height = getTargetRect("height") - 40 - 30 - 35 - 34; $($targetId + " .jexcel_content").css("max-height", jexcel_content_height); $($targetId + " .jexcel_content").css("width", "100%"); }); } function drawExcel(target) { let $targetId = "#" + target; if ($($targetId).length > 0 && $($targetId)[0].jexcel) { $($targetId)[0].jexcel.destroy(); } $($targetId).spreadsheet( $.extend( {}, { columns: getColumns(), data: getExcelData() }, getOptions() ) ); let jexcel_content_height = getTargetRect("height") - 40 - 30 - 35 - 34; $($targetId + " .jexcel_content").css("max-height", jexcel_content_height); $($targetId + " .jexcel_content").css("width", "100%"); } return { setTargetId, getTargetId, setTargetRect, getTargetRect, setDefaultTargetRect, setExcelData, getExcelData, updateDataAtIndex, getDataAtIndex, setColumns, getColumns, setColumnWidth, setOptions, getOptions, startObserver, stopObserver, drawExcel, drawResizedExcel }; })(); function csvExport() { $(".jexcel_toolbar_item.material-icons.fa.fa-save").click(); } +(function ($) { "use strict"; $(document).on("create.language_pack_list", function (event) { var $target = $(event.target); if ($target.jstree(true)) { $target.jstree("destroy").html("

조회된 데이터가 없습니다.

"); } // 언어팩 파일 목록 조회 $.get("/auth-sche/language-config/packs/files").done(function (response) { // jsTree 데이터 구조 생성 var treeData = { data: { data: "A-RMS - Language Packs (전체)", state: "open", attr: { rel: "drive" }, children: response.map((file) => ({ data: file.fileName, attr: { rel: "default" } })) } }; console.log("treeData => ", treeData); $target .on("select_node.jstree", function (e, data) { // 선택된 노드의 정보 var selectedNode = data.inst.get_json()[0]; var selectedNodeData = data.rslt.obj; var selectedNodeType = selectedNodeData.attr("rel"); // 선택된 노드가 파일인 경우 (rel이 'default'인 경우) if (selectedNodeType === "default") { var fileName = data.inst.get_text(data.rslt.obj); const fileNameExceptExt = fileName.replace(".json", ""); selectedLanguageCode = fileNameExceptExt; senderSetting(fileName); $("#addLanguageKey").removeClass("hidden"); $("#languagePack_delete_modal #languagePackForm_delete input[name='languageCode']").val(fileNameExceptExt); getLanguagePack(fileNameExceptExt); } else if (selectedNodeType === "drive") { // 루트 선택 senderSetting("언어팩 전체"); $("#addLanguageKey").addClass("hidden"); selectedLanguageCode = "all"; getAllContents(); } }) .on("loaded.jstree", function (e, data) { $("#alog").append(data.func + "
"); $("li:not([rel='drive']).jstree-open > a > .jstree-icon").css( "background-image", "url(../reference/jquery-plugins/jstree-v.pre1.0/themes/toolbar_open.png)" ); $("li:not([rel='drive']).jstree-closed > a > .jstree-icon").css( "background-image", "url(../reference/jquery-plugins/jstree-v.pre1.0/themes/ic_explorer.png)" ); }) .jstree({ plugins: ["themes", "json_data", "ui", "crrm", "dnd", "types"], themes: { theme: ["lightblue4"] }, json_data: treeData, types: { types: { default: { valid_children: "none", icon: { image: "../reference/jquery-plugins/jstree-v.pre1.0/themes/attibutes.png" } }, drive: { valid_children: ["default"], icon: { image: "../reference/jquery-plugins/jstree-v.pre1.0/themes/home.png" }, start_drag: false, move_node: false, delete_node: false, remove: false } } } }); }); }); })(jQuery); function getAllContents() { $.get("/auth-sche/language-config/packs/all-contents").done(function (response) { console.log(`getAllLanguagePacks :: response =>`, response); // 동적으로 columnList 생성 var columnList = generateColumnListByAllContents(response); // 데이터 파싱 var excelData = parseLanguageDataByAllContents(response); drawExcelByType("drive", "modal_excel", columnList, excelData); }); } async function getLanguagePack(languageCode) { try { const response = await $.get("/auth-sche/language-config/packs/language/" + languageCode); console.log(`getLanguagePack :: ${languageCode} =>`, response); let columnList = null; let parsedExcelData = null; if (languageCode === "ko") { columnList = generateSingleLangColumnList(); parsedExcelData = parseSingleLangData(response); } else { columnList = await generateSingleLangColumnListWithReferenceLangPack(languageCode); parsedExcelData = await parseSingleLangDataWithReferenceLang(response); } drawExcelByType("default", "modal_excel", columnList, parsedExcelData); } catch (error) { console.error("Error in getLanguagePack:", error); } } ///////////////////////////////// // 함수. 서버에서 기본 언어팩 가져오기 ///////////////////////////////// function getReferenceLanguagePack(languageCode) { return $.get("/auth-sche/language-config/packs/language/" + languageCode) .then(function (response) { if (response && response.language && response.languagePack) { setReferenceLanguage(response.language, response.languagePack); } else { console.error("Invalid response from getReferenceLanguagePack:", response); } return response; }) .catch(function (error) { console.error("Error fetching language pack:", error); }); } function generateSingleLangColumnList() { return [ { type: "text", title: "키 (key)", name: "key", wRatio: 0.5, readOnly: true }, { type: "text", title: "값(value)", name: "value", wRatio: 0.5 } ]; } async function generateSingleLangColumnListWithReferenceLangPack(languageCode) { console.log("generateSingleLangColumnListWithReferenceLangPack :: languageCode =>", languageCode); const languageDisplayName = await getLanguageDisplayName(languageCode); const formattedName = languageCode.toUpperCase(); console.log("generateSingleLangColumnListWithReferenceLangPack :: languageDisplayName =>", languageDisplayName); return [ { type: "text", title: "KO (한국어)", name: "ko", wRatio: 0.3, readOnly: true }, { type: "text", title: `${formattedName} (${languageDisplayName})`, name: "value", wRatio: 0.3 }, { type: "text", title: "키 (key)", name: "key", wRatio: 0.4, readOnly: true } ]; } function getLanguageDisplayName(languageCode) { const displayNameMap = { en: "영어", ja: "일본어", ko: "한국어", zh: "중국어" // Add more as needed }; return displayNameMap[languageCode] || languageCode; } function extractLanguageCode(input) { const match = input.match(/^[^(]+/); // 괄호 '(' 앞의 모든 내용 추출 return match ? match[0].trim().toLowerCase() : null; // 양쪽 공백 제거 후 소문자로 변환 } function generateColumnListByAllContents(response) { const columnList = []; let colIdx = 0; columnList.push({ readOnly: true, type: "text", title: "KO (한국어)", name: "ko" }); langPacksColumnList["ko"] = colIdx; const languageNames = response.map((item) => item.language); languageNames.forEach((language) => { if (language !== "ko") { langPacksColumnList[`${language}`] = ++colIdx; const formattedName = language.toUpperCase(); columnList.push({ type: "text", title: `${formattedName} (${getLanguageDisplayName(language)})`, name: language // readOnly: true }); } }); // Calculate wRatio for 'text' type columns const textColumnCount = columnList.filter((col) => col.type === "text").length; if (textColumnCount > 0) { const wRatioValue = Math.round((1 / textColumnCount) * 100) / 100; // Round to two decimal places columnList.forEach((col) => { if (col.type === "text") { col.wRatio = wRatioValue; } }); } // Add the hidden key column columnList.push({ type: "hidden", title: "키 (key)", name: "key" }); langPacksColumnList["key"] = ++colIdx; return columnList; } function parseLanguageDataByAllContents(response) { const languagePacks = {}; const result = []; // 최종 결과 배열 // 언어별 데이터 추출 response.forEach((item) => { const { language, languagePack } = item; languagePacks[language] = languagePack; }); const referenceLanguage = "ko"; // 기준 언어 (필요시 다른 언어로 변경 가능) const referenceData = languagePacks[referenceLanguage]; setReferenceLanguage(referenceLanguage, referenceData); if (!referenceData) { throw new Error(`기준 언어(${referenceLanguage}) 데이터가 존재하지 않습니다.`); } Object.keys(referenceLanguagePack.languagePack).forEach((key) => { const row = { key }; // 현재 키를 기반으로 결과 생성 // 각 언어에 해당 키 값을 추가 Object.keys(languagePacks).forEach((language) => { row[language] = languagePacks[language][key] || ""; // 언어 데이터가 없으면 빈 문자열 }); result.push(row); }); return result; } function parseSingleLangData(responseByOneLang) { const parsedData = []; const languagePack = responseByOneLang.languagePack; const sortedKeys = Object.keys(languagePack).sort(); for (const key of sortedKeys) { parsedData.push({ key: key, value: languagePack[key] }); } return parsedData; } async function parseSingleLangDataWithReferenceLang(responseByOneLang) { const parsedData = []; const languagePack = responseByOneLang.languagePack; if (!referenceLanguagePack || referenceLanguagePack.language === null) { await getReferenceLanguagePack("ko"); } const $referenceLanguagePack = referenceLanguagePack.languagePack; if (!$referenceLanguagePack) { console.error("Reference language pack is still not initialized."); return []; } for (const key in $referenceLanguagePack) { if (Object.hasOwnProperty.call($referenceLanguagePack, key)) { parsedData.push({ key: key, ko: $referenceLanguagePack[key] || "", value: languagePack[key] || "" }); } } return parsedData; } function drawExcelByType(type, target, columnList, excelData) { if (!columnList) { return; } var customOption = { toolbar: [], // 툴바 사용하지 않음. search: true, contextMenu: [], pagination: 50, allowInsertRow: false, allowInsertColumn: false, // passive 이벤트 리스너 설정으로 성능 최적화 onload: function (element) {}, updateTable: function (instance, cell, col, row, val, id) { cell.style.textAlign = "left"; cell.style.whiteSpace = "normal"; }, onchange: function (instance, cell, col, row, val, id) { var changedRowData = SpreadsheetFunctions.getDataAtIndex(row); isChanged = true; if (type === "default") { changedRowData.value = val; SpreadsheetFunctions.updateDataAtIndex(row, changedRowData); } else { let colName = $("#modal_excel")[0].jexcel.getHeader(col); let langCode = extractLanguageCode(colName); changedLang.add(langCode); changedRowData[langCode] = val; SpreadsheetFunctions.updateDataAtIndex(row, changedRowData); } }, oneditionstart: function () { SpreadsheetFunctions.isEditingCell = true; SpreadsheetFunctions.stopObserver(); }, oneditionend: function () { SpreadsheetFunctions.isEditingCell = false; SpreadsheetFunctions.startObserver(); } }; SpreadsheetFunctions.setTargetId(target); SpreadsheetFunctions.setDefaultTargetRect(); SpreadsheetFunctions.setColumns(columnList); SpreadsheetFunctions.setColumnWidth(SpreadsheetFunctions.getTargetRect("width")); SpreadsheetFunctions.setOptions(customOption); SpreadsheetFunctions.startObserver(); SpreadsheetFunctions.setExcelData(excelData); SpreadsheetFunctions.drawExcel(SpreadsheetFunctions.getTargetId()); } //////////////////////////////////////// // referenceLanguagePack 업데이트 함수 //////////////////////////////////////// function setReferenceLanguage(language, languagePack) { if (!language || !languagePack) { console.error("Invalid language or languagePack:", language, languagePack); return; } // languagePack의 키를 알파벳 순으로 정렬 const sortedLanguagePack = Object.keys(languagePack) .sort() // 키를 알파벳 순으로 정렬 .reduce((acc, key) => { acc[key] = languagePack[key]; // 정렬된 순서로 새로운 객체 생성 return acc; }, {}); // referenceLanguagePack 업데이트 referenceLanguagePack.language = language; referenceLanguagePack.languagePack = sortedLanguagePack; console.log("referenceLanguagePack is updated"); } function btnClickEvent() { $("#updateLanguagePack").on("click", function () { if (!isChanged) { jError("수정된 값이 없습니다."); return; } let arrayData = $("#modal_excel")[0].jexcel.getData(); if (!selectedLanguageCode || selectedLanguageCode === "all") { console.log("selectedLanguageCode => ", selectedLanguageCode); let changedLangArr = [...changedLang]; updateLanguagePacks(changedLangArr); } else { updateSingleLanguagePack(selectedLanguageCode, convertSheetDataToAnArrayOfKeyValue(arrayData)); } }); $("#checkKeyExist").on("click", async function () { // 모달 UI 초기화 $("#languagePackForm_add_key fieldset .input-group input").removeClass("is-invalid"); isValidCheck.modal = false; isValidCheck.gc = false; let formDataArray = $("#languagePackForm_add_key").serializeArray(); let elementIdListOfDuplicatedKey = findDuplicateKeysOnModal(formDataArray, "additionalKey"); let keys, swappedFormArray; if (elementIdListOfDuplicatedKey.length === 0) { isValidCheck.modal = true; keys = getAdditionalKeyValues(formDataArray, "additionalKey"); swappedFormArray = valueElementId(formDataArray); } else { elementIdListOfDuplicatedKey.forEach((element) => { $(`#${element}`).addClass("is-invalid"); }); } try { const isDuplicatedOnGC = await checkLanguageKeyExistsOnRepo(selectedLanguageCode, keys); if (isDuplicatedOnGC && isDuplicatedOnGC.length === 0) { isValidCheck.gc = true; $("#uniqueCheckComplete").removeClass("hidden"); } else { console.log("Duplicated keys =>", isDuplicatedOnGC); isDuplicatedOnGC.forEach((key) => { let duplicatedFormId = swappedFormArray[key]; if (duplicatedFormId) { $(`#${duplicatedFormId}`).addClass("is-invalid"); } }); } } catch (error) { console.error("Error during global config check:", error); } }); $("#add_languagePack_btn").on("click", function () { console.log("languageConfig :: add_languagePack_btn is clicked"); let formDataArray = $("#languagePack_add_modal #languagePackForm_add").serializeArray(); if (formDataArray.length === 0) { console.log("추가할 Language Code 가 없습니다."); } let langCodeForAddition = formDataArray[0].value; console.log("langCodeForAddition => ", langCodeForAddition); addSingleLanguagePack(langCodeForAddition, [{}]); }); $("#delete_languagePack_btn").on("click", function () { if (selectedLanguageCode === "all") { jError("전체 언어팩 일괄 삭제는 지원하지 않습니다. 관리자에 문의하세요."); } console.log("languageConfig :: delete_languagePack_btn is clicked"); let formDataArray = $("#languagePack_delete_modal #languagePackForm_delete").serializeArray(); let langCodeForDelete = formDataArray[0].value; deleteSingleLanguagePack(langCodeForDelete); }); $("#languagePack_add_modal").on("show.bs.modal", function () { $("#languagePack_add_modal #languagePackForm_add input[name='languageCode']").val(""); }); $("#refreshLanguagePacks").on("click", function () { refreshLanguagePacks(); }); $("#languagePack_add_key_modal") .on("hidden.bs.modal", function () { dynamicPairContainer.empty(); // 동적 필드셋 초기화 pairCounter = 0; // 카운터 초기화 }) .on("show.bs.modal", function () { console.log("add New Empty Pair when modal is shown"); $("#addNewEmptyPair").trigger("click"); // 1개 추가 }); dynamicPairContainer.on("click", ".removePair", function () { const pairId = $(this).data("pair-id"); $(`#pair-${pairId}`).remove(); console.log(`Removed pair-${pairId}`); }); $("#addNewEmptyPair").on("click", function () { addNewEmptyPairHtmlElement(); $("#uniqueCheckComplete").addClass("hidden"); isValidCheck.modal = false; isValidCheck.gc = false; }); $("#add_key_pair_btn").on("click", function (event) { if (!isValidCheck.gc || !isValidCheck.modal) { jError("키(Key) 중복체크를 해주세요."); event.preventDefault(); event.stopPropagation(); return; } const addedPairs = transformKeyValuePairs($("#languagePackForm_add_key").serializeArray()); if (addedPairs.length === 0) { // 추가할 Key-Value가 없는 경우 jError("저장할 Key 값이 없습니다."); // 이벤트 전파 및 기본 동작 멈춤 event.preventDefault(); event.stopPropagation(); return; } let excelData = convertSheetDataToAnArrayOfKeyValue($("#modal_excel")[0].jexcel.getData()); let mergedData = excelData.concat(addedPairs); if (selectedLanguageCode === "ko") { // 기준언어는 언어팩 업데이트. updateSingleLanguagePack(selectedLanguageCode, mergedData); refreshPacksAndGetSingleLanguagePack(selectedLanguageCode); } else { //1st update updateSingleLanguagePack(selectedLanguageCode, mergedData); //2nd update const referencePackArray = objectToKeyValueArray(referenceLanguagePack.languagePack); const emptyValues = addedPairs.map((pair) => { const key = Object.keys(pair)[0]; return { [key]: "" }; }); updateSingleLanguagePack("ko", referencePackArray.concat(emptyValues)); refreshPacksAndGetSingleLanguagePack(selectedLanguageCode); } }); } ////////////////////////////////////////////// // converting format sheetData(Array) to another array of { key : value } ////////////////////////////////////////////// function convertSheetDataToAnArrayOfKeyValue(arrayData) { // 변환 로직 const transformedData = arrayData.map((item) => { if (Array.isArray(item) && item.length >= 2) { if (item.length === 3) { const key = item[2]; const value = item[1]; return { [key]: value }; } else { return { [item[0]]: item[1] }; } } else { throw new Error("Invalid item format: Expected array with at least 2 elements"); } }); return transformedData; } function updateLanguagePacks(changedLangArr) { if (!changedLangArr || changedLangArr.length === 0) { jError("업데이트할 내용이 없습니다."); } console.log("updateLanguagePacks :: changedLangArr => ", changedLangArr); let idxOfKey = langPacksColumnList["key"]; let keyArr = $("#modal_excel")[0].jexcel.getColumnData(idxOfKey); changedLangArr.forEach((langCode) => { let idxOfLang = langPacksColumnList[langCode]; let langDataArr = $("#modal_excel")[0].jexcel.getColumnData(idxOfLang); let mergedLangPack = keyArr.map((key, index) => ({ [key]: langDataArr[index] })); $.ajax({ url: "/auth-sche/language-config/packs/language/" + langCode, type: "PUT", data: JSON.stringify(mergedLangPack), contentType: "application/json; charset=utf-8", async: false, // 동기 처리 success: function (response) { console.log(`${langCode}.json is updated`); }, error: function (error) { console.error("Error updating language pack:", error); }, complete: function () { jSuccess(`${langCode}.json 업데이트 완료`); } }); }); isChanged = false; changedLang.clear(); } // update LanguagePack function updateSingleLanguagePack(languageCode, languagePack) { console.log(`updateSingleLanguagePack :: languageCode => ${languageCode}, languagePack => `, languagePack); $.ajax({ url: "/auth-sche/language-config/packs/language/" + languageCode, type: "PUT", data: JSON.stringify(languagePack), contentType: "application/json; charset=utf-8", async: false, success: function (response) { console.log("updateSingleLanguagePack :: response =>", response); isChanged = false; isValidCheck.modal = false; isValidCheck.gc = false; jSuccess(`${languageCode}.json is updated`); }, error: function (error) { console.error("Error updating language pack:", error); } }); } // create LanguagePack (empty contents) function addSingleLanguagePack(languageCode, languagePack) { console.log(`addSingleLanguagePack :: languageCode => ${languageCode}, languagePack => `, languagePack); $.ajax({ url: "/auth-sche/language-config/packs/language/" + languageCode, type: "PUT", data: JSON.stringify(languagePack), contentType: "application/json; charset=utf-8", success: function (response) { console.log("updateSingleLanguagePack :: response =>", response); $("#language_pack_list").trigger("create.language_pack_list"); }, error: function (error) { console.error("Error updating language pack:", error); } }); } function deleteSingleLanguagePack(languageCode) { console.log(`deleteSingleLanguagePack :: languageCode => ${languageCode}`); $.ajax({ url: "/auth-sche/language-config/packs/language/" + languageCode, type: "DELETE", contentType: "application/json; charset=utf-8", success: function (response) { console.log("deleteSingleLanguagePack :: response =>", response); // refresh jsTree $("#language_pack_list").trigger("create.language_pack_list"); }, error: function (error) { console.error("Error deleting language pack:", error); } }); } function refreshLanguagePacks() { $.get("/auth-sche/language-config/packs/all-contents/refresh").done(function (response) { console.log(`refreshLanguagePacks :: response =>`, response); // refresh jsTree $("#language_pack_list").trigger("create.language_pack_list"); var columnList = generateColumnListByAllContents(response); var excelData = parseLanguageDataByAllContents(response); drawExcelByType("drive", "modal_excel", columnList, excelData); }); } function refreshPacksAndGetSingleLanguagePack(languageCode) { $.get("/auth-sche/language-config/packs/all-contents/refresh").done(function (response) { getLanguagePack(languageCode); }); } ///////////////////////////////////////////////// // 항목추가 모달 :: 키(key)-값(value) 빈 요소 추가 ///////////////////////////////////////////////// function addNewEmptyPairHtmlElement() { pairCounter++; const newPairHtml = `
`; dynamicPairContainer.append(newPairHtml); } function senderSetting(textContents) { $("#sender-language").css("color", "#a4c6ff").text(textContents); $(".chat-message-body").css("border-left", "2px solid #e5603b"); $(".chat-message-body .arrow").css("border-right", "5px solid #e5603b"); $(".sender-contents").text(textContents).css("color", "#a4c6ff"); } ///////////////////////// // 언어팩 키(key) 중복 체크 ///////////////////////// async function checkLanguageKeyExistsOnRepo(languageCode, keys) { return new Promise((resolve, reject) => { $.ajax({ url: `/auth-sche/language-config/packs/language/${languageCode}/keys/exists`, type: "GET", traditional: true, data: { keys: keys }, success: function (response) { console.log("checkLanguageKeyExists :: response =>", response); if (response && response.length === 0) { console.log("There is no duplicated key"); } else { console.log("Duplicated keys => ", response); } resolve(response); }, error: function (error) { console.error("Error checking language key exists:", error); reject(error); } }); }); } function valueElementId(serializedArray) { if (serializedArray.length === 0) return {}; return serializedArray .filter((item) => item.name.startsWith("additionalKey")) // "additionalKey-*" 필터링 .reduce((acc, item) => { acc[item.value] = item.name; return acc; }, {}); } function getAdditionalKeyValues(data, prefix) { return data .filter((item) => item.name.startsWith(prefix)) // "additionalKey-"로 시작하는 항목 필터링 .map((item) => item.value); // value 값만 추출 } ////////////////////////////// // 모달에서 key 중복 여부 확인 ////////////////////////////// function findDuplicateKeysOnModal(data, prefix) { const valueToNamesMap = new Map(); const duplicateNames = new Set(); data .filter((item) => item.name.startsWith(prefix)) .forEach((item) => { if (valueToNamesMap.has(item.value)) { valueToNamesMap.get(item.value).push(item.name); valueToNamesMap.get(item.value).forEach((name) => { duplicateNames.add(name); }); } else { valueToNamesMap.set(item.value, [item.name]); } }); return Array.from(duplicateNames); } function transformKeyValuePairs(data) { const keyPrefix = "additionalKey"; const valuePrefix = "additionalValue"; const result = []; // Key와 Value를 매핑 const keyMap = new Map(); data.forEach((item) => { if (item.name.startsWith(keyPrefix)) { const index = item.name.split("-")[1]; // Key의 번호를 가져옴 if (!keyMap.has(index)) { keyMap.set(index, { key: item.value, value: "" }); // Key 저장, 기본 value를 ""로 설정 } else { keyMap.get(index).key = item.value; // 기존 객체에 Key 설정 } } else if (item.name.startsWith(valuePrefix)) { const index = item.name.split("-")[1]; // Value의 번호를 가져옴 if (!keyMap.has(index)) { keyMap.set(index, { key: "", value: item.value }); // 기본 key를 ""로 설정 } else { keyMap.get(index).value = item.value; // 기존 객체에 Value 설정 } } }); // Key-Value 쌍을 배열에 추가 keyMap.forEach((pair) => { // value가 항상 빈값이라도 존재하도록 보장 if (pair.key) { result.push({ [pair.key]: pair.value }); // 빈 문자열도 포함해 추가 } }); return result; } function objectToKeyValueArray(obj) { return Object.entries(obj).map(([key, value]) => ({ [key]: value })); }