cbf3066a56
Summernote 에디터 스타일 CSS 추가 - 텍스트 및 컴포넌트 스타일 정의 OpenAPI POC JS 파일 추가 - API 스펙 빌더 및 스텝별 렌더 구현
123 lines
5.5 KiB
JavaScript
123 lines
5.5 KiB
JavaScript
/*!
|
|
* djb-swagger-i18n.js
|
|
* Swagger UI 영문 라벨을 한글로 치환하는 i18n 패치 (방법 B - DOM patch)
|
|
* 배포 경로 권장: static/plugins/swaggerUI/djb-swagger-i18n.js
|
|
* index.html 의 swagger-initializer.js 직전 또는 직후에 <script> 로 로드
|
|
*
|
|
* ?lang=en 쿼리스트링이 있으면 패치 비활성화 (원문 보기)
|
|
* 매핑 카탈로그는 01-i18n-mapping/i18n-strings.csv 와 동기 유지
|
|
*/
|
|
(function (window) {
|
|
'use strict';
|
|
|
|
// ── 비활성화 옵션 ──
|
|
if (/[?&]lang=en\b/.test(window.location.search)) return;
|
|
|
|
// ── 매핑 (key 는 디버깅용, 실제 비교는 EN 문자열 일치) ──
|
|
var I18N_MAP = {
|
|
// P0 — OAuth2 모달 본문
|
|
'auth.modal.title': { en: 'Available authorizations', ko: '사용 가능한 인증' },
|
|
'auth.scopes.description': {
|
|
en: 'Scopes are used to grant an application different levels of access to data on behalf of the end user. Each API may declare one or more scopes.',
|
|
ko: '스코프는 최종 사용자를 대신하여 애플리케이션이 데이터에 접근할 수 있는 권한 수준을 부여합니다. 각 API는 하나 이상의 스코프를 선언할 수 있습니다.'
|
|
},
|
|
'auth.scopes.swagger_grant': {
|
|
en: 'API requires the following scopes. Select which ones you want to grant to Swagger UI.',
|
|
ko: '이 API 는 아래 스코프가 필요합니다. Swagger UI 에 부여할 스코프를 선택하세요.'
|
|
},
|
|
'auth.flow.clientCredentials': { en: 'OAuth2 client credentials flow', ko: 'OAuth2 클라이언트 자격증명 흐름' },
|
|
'auth.flow.implicit': { en: 'OAuth2 implicit flow', ko: 'OAuth2 암묵적 흐름' },
|
|
'auth.flow.password': { en: 'OAuth2 password flow', ko: 'OAuth2 비밀번호 흐름' },
|
|
'auth.flow.authorizationCode': { en: 'OAuth2 authorization code flow', ko: 'OAuth2 인가 코드 흐름' },
|
|
'auth.field.tokenUrl': { en: 'Token URL:', ko: '토큰 URL:' },
|
|
'auth.field.flow': { en: 'Flow:', ko: '흐름:' },
|
|
'auth.field.clientId': { en: 'client_id:', ko: '클라이언트 ID (client_id):' },
|
|
'auth.field.clientSecret': { en: 'client_secret:',ko: '클라이언트 시크릿 (client_secret):' },
|
|
'auth.field.scopes': { en: 'Scopes:', ko: '스코프:' },
|
|
'auth.action.selectAll': { en: 'select all', ko: '모두 선택' },
|
|
'auth.action.selectNone': { en: 'select none', ko: '선택 해제' },
|
|
'auth.action.authorize': { en: 'Authorize', ko: '인증' },
|
|
'auth.action.close': { en: 'Close', ko: '닫기' },
|
|
'auth.action.logout': { en: 'Logout', ko: '로그아웃' },
|
|
'auth.modal.authorized': { en: 'authorized', ko: '인증됨' },
|
|
|
|
// P1 — 기타 인증 흐름
|
|
'auth.scheme.apiKey': { en: 'API key', ko: 'API 키' },
|
|
'auth.field.name': { en: 'name:', ko: '이름:' },
|
|
'auth.field.in': { en: 'in:', ko: '위치:' },
|
|
'auth.field.value': { en: 'Value:', ko: '값:' },
|
|
'basic.field.username': { en: 'Username:',ko: '사용자 ID:' },
|
|
'basic.field.password': { en: 'Password:',ko: '비밀번호:' }
|
|
// P2 (오퍼레이션/응답) 는 필요 시 추가
|
|
};
|
|
|
|
// 빠른 lookup 을 위해 EN → KO 인덱스 사전 생성
|
|
var EN_TO_KO = Object.create(null);
|
|
Object.keys(I18N_MAP).forEach(function (k) {
|
|
var e = I18N_MAP[k];
|
|
EN_TO_KO[e.en] = e.ko;
|
|
});
|
|
|
|
// ── 치환 대상 노드 식별 + 치환 ──
|
|
function translateNode(node) {
|
|
if (!node) return;
|
|
if (node.nodeType === Node.TEXT_NODE) {
|
|
var raw = node.nodeValue;
|
|
if (!raw) return;
|
|
var trimmed = raw.trim();
|
|
if (!trimmed) return;
|
|
// 1) 완전 일치 (가장 안전)
|
|
if (EN_TO_KO[trimmed]) {
|
|
node.nodeValue = raw.replace(trimmed, EN_TO_KO[trimmed]);
|
|
return;
|
|
}
|
|
// 2) 라벨 colon 패턴: "Token URL:" 같이 끝이 ":" 인 짧은 라벨
|
|
// (불필요 — 1번 완전 일치로 대부분 커버)
|
|
return;
|
|
}
|
|
if (node.nodeType !== Node.ELEMENT_NODE) return;
|
|
if (node.tagName === 'SCRIPT' || node.tagName === 'STYLE') return;
|
|
|
|
// input placeholder / button title 도 일부 케이스에 대비
|
|
if (node.tagName === 'INPUT' && node.placeholder && EN_TO_KO[node.placeholder.trim()]) {
|
|
node.placeholder = EN_TO_KO[node.placeholder.trim()];
|
|
}
|
|
|
|
var i, child = node.childNodes, len = child.length;
|
|
for (i = 0; i < len; i++) translateNode(child[i]);
|
|
}
|
|
|
|
function translateAll() {
|
|
var root = document.getElementById('swagger-ui') || document.body;
|
|
translateNode(root);
|
|
}
|
|
|
|
// ── MutationObserver — SwaggerUI 가 동적으로 DOM 을 다시 그릴 때마다 재적용 ──
|
|
var observer = new MutationObserver(function (mutations) {
|
|
for (var i = 0; i < mutations.length; i++) {
|
|
var m = mutations[i];
|
|
if (m.addedNodes && m.addedNodes.length) {
|
|
for (var j = 0; j < m.addedNodes.length; j++) translateNode(m.addedNodes[j]);
|
|
}
|
|
if (m.type === 'characterData') {
|
|
translateNode(m.target);
|
|
}
|
|
}
|
|
});
|
|
|
|
function start() {
|
|
translateAll();
|
|
observer.observe(document.body, {
|
|
childList: true,
|
|
subtree: true,
|
|
characterData: true
|
|
});
|
|
}
|
|
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', start);
|
|
} else {
|
|
start();
|
|
}
|
|
})(window);
|