331 lines
9.5 KiB
Markdown
331 lines
9.5 KiB
Markdown
# 다국어 키 추출 (extract-i18n-keys)
|
|
|
|
레이아웃 JSON 파일에서 사용된 다국어 키를 추출하고 언어 파일과 비교하여 누락된 키를 보고합니다.
|
|
|
|
## 0단계: 추출 대상 판별
|
|
|
|
```text
|
|
⚠️ CRITICAL: 추출 대상 경로 확인
|
|
```
|
|
|
|
### 대상 경로 유형
|
|
|
|
| 경로 패턴 | 유형 | 언어 파일 위치 |
|
|
| --------- | ---- | -------------- |
|
|
| `modules/[vendor-module]/resources/layouts/**/*.json` | 모듈 레이아웃 | `modules/[vendor-module]/resources/lang/*.json` |
|
|
| `modules/_bundled/[vendor-module]/resources/layouts/**/*.json` | _bundled 모듈 레이아웃 | `modules/_bundled/[vendor-module]/resources/lang/*.json` |
|
|
| `templates/[vendor-template]/layouts/**/*.json` | 템플릿 레이아웃 | `templates/[vendor-template]/lang/*.json` |
|
|
| `templates/_bundled/[vendor-template]/layouts/**/*.json` | _bundled 템플릿 레이아웃 | `templates/_bundled/[vendor-template]/lang/*.json` |
|
|
| `resources/layouts/**/*.json` | 코어 레이아웃 | `lang/{ko,en}.json` (+ `lang/partial/{ko,en}/*.json`) |
|
|
|
|
### $ARGUMENTS 처리
|
|
|
|
- 경로가 지정된 경우: 해당 경로의 JSON 파일만 대상
|
|
- 경로가 지정되지 않은 경우: 사용자에게 대상 경로 문의
|
|
|
|
## 1단계: 레이아웃 파일 수집
|
|
|
|
### 1.1 대상 파일 탐색
|
|
|
|
```bash
|
|
# 모듈 레이아웃 예시
|
|
find modules/sirsoft-ecommerce/resources/layouts -name "*.json" -type f
|
|
|
|
# 템플릿 레이아웃 예시
|
|
find templates/sirsoft-admin_basic/layouts -name "*.json" -type f
|
|
```
|
|
|
|
### 1.2 파일 목록 생성
|
|
|
|
수집된 파일 목록을 정리:
|
|
- 메인 레이아웃 파일
|
|
- partials 디렉토리 내 파일
|
|
- 중첩된 모든 JSON 파일
|
|
|
|
## 2단계: 다국어 키 추출
|
|
|
|
### 2.1 추출 패턴
|
|
|
|
다음 패턴의 다국어 키를 추출합니다:
|
|
|
|
| 패턴 | 설명 | 예시 |
|
|
| ---- | ---- | ---- |
|
|
| `$t:namespace.key.path` | 즉시 번역 | `$t:sirsoft-ecommerce.admin.product.name` |
|
|
| `$t:defer:namespace.key.path` | 지연 번역 | `$t:defer:common.save` |
|
|
|
|
### 2.2 추출 정규식
|
|
|
|
```javascript
|
|
// $t: 패턴 추출 (defer 포함)
|
|
const regex = /\$t:(?:defer:)?([a-zA-Z][a-zA-Z0-9_.-]*(?:\.[a-zA-Z0-9_-]+)+)/g;
|
|
```
|
|
|
|
### 2.3 키 분류
|
|
|
|
추출된 키를 네임스페이스별로 분류:
|
|
|
|
| 키 패턴 | 분류 | 저장 위치 |
|
|
| ------- | ---- | --------- |
|
|
| `sirsoft-ecommerce.*` | 모듈 전용 | `modules/sirsoft-ecommerce/resources/lang/*.json` |
|
|
| `common.*` | 공통 키 | 코어 또는 모듈 lang 파일 |
|
|
| `messages.*` | 메시지 | 코어 또는 모듈 lang 파일 |
|
|
| `currency.*` | 통화 | 코어 또는 모듈 lang 파일 |
|
|
| `validation.*` | 검증 | 코어 또는 모듈 lang 파일 |
|
|
|
|
### 2.4 모듈 네임스페이스 검증 (CRITICAL)
|
|
|
|
모듈 레이아웃에서 사용된 다국어 키가 올바른 네임스페이스를 사용하는지 검증합니다.
|
|
|
|
```text
|
|
⚠️ CRITICAL: 모듈 레이아웃에서 다국어 키 사용 시 반드시 모듈 식별자 접두사 포함
|
|
```
|
|
|
|
| ❌ 금지 | ✅ 올바른 사용 |
|
|
| -------- | --------------- |
|
|
| `$t:common.save` (모듈에서 코어 키 직접 참조) | `$t:sirsoft-ecommerce.common.save` (모듈 식별자 접두사) |
|
|
| `$t:admin.product.name` (네임스페이스 누락) | `$t:sirsoft-ecommerce.admin.product.name` |
|
|
|
|
**검증 항목**:
|
|
|
|
- 모듈 레이아웃 내 `$t:` 키가 해당 모듈 식별자로 시작하는지 확인
|
|
- `$t:common.*` 형태로 코어 키를 직접 참조하면 경고 (모듈 lang 파일이 아닌 코어 lang에서 찾게 됨)
|
|
- 예외: `$t:common.*`이 코어 키를 의도적으로 참조하는 경우 (명시적 확인 필요)
|
|
|
|
## 3단계: 언어 파일 분석
|
|
|
|
### 3.1 언어 파일 읽기
|
|
|
|
```bash
|
|
# 모듈 언어 파일
|
|
modules/[vendor-module]/resources/lang/ko.json
|
|
modules/[vendor-module]/resources/lang/en.json
|
|
|
|
# 코어 프론트엔드 언어 파일 (모듈/플러그인과 동일한 구조: 엔트리 + partial 분할)
|
|
lang/ko.json
|
|
lang/en.json
|
|
lang/partial/ko/*.json # 선택적 — 엔트리에서 $partial 디렉티브로 참조
|
|
lang/partial/en/*.json
|
|
```
|
|
|
|
### 3.2 기존 키 추출
|
|
|
|
JSON 파일에서 모든 키 경로를 추출:
|
|
|
|
```javascript
|
|
// 중첩된 객체에서 키 경로 추출
|
|
function extractKeys(obj, prefix = '') {
|
|
const keys = [];
|
|
for (const [key, value] of Object.entries(obj)) {
|
|
const path = prefix ? `${prefix}.${key}` : key;
|
|
if (typeof value === 'object' && value !== null) {
|
|
keys.push(...extractKeys(value, path));
|
|
} else {
|
|
keys.push(path);
|
|
}
|
|
}
|
|
return keys;
|
|
}
|
|
```
|
|
|
|
## 4단계: 비교 및 분석
|
|
|
|
### 4.1 누락 키 식별
|
|
|
|
레이아웃에서 사용된 키 vs 언어 파일에 존재하는 키 비교:
|
|
|
|
```text
|
|
사용된 키 - 존재하는 키 = 누락된 키
|
|
```
|
|
|
|
### 4.2 미사용 키 식별 (선택)
|
|
|
|
언어 파일에 존재하지만 레이아웃에서 사용되지 않는 키:
|
|
|
|
```text
|
|
존재하는 키 - 사용된 키 = 미사용 키
|
|
```
|
|
|
|
## 5단계: 결과 보고
|
|
|
|
### 5.1 보고서 형식
|
|
|
|
```text
|
|
## 다국어 키 추출 결과
|
|
|
|
### 추출 대상
|
|
- 레이아웃 경로: [경로]
|
|
- 검사 파일 수: X개
|
|
- 언어 파일: ko.json, en.json
|
|
|
|
### 추출된 키 요약
|
|
- 총 사용된 키: XXX개
|
|
- 모듈 전용 키 (sirsoft-ecommerce.*): XXX개
|
|
- 공통 키 (common.*): XX개
|
|
- 메시지 키 (messages.*): XX개
|
|
- 기타 키: XX개
|
|
|
|
### 언어 파일 현황
|
|
- ko.json 존재 키: XXX개
|
|
- en.json 존재 키: XXX개
|
|
|
|
### 누락된 키 (CRITICAL)
|
|
- 총 누락: XX개 (XX.X% 누락률)
|
|
|
|
#### 모듈 전용 키 누락 (sirsoft-ecommerce.*)
|
|
| 키 | 사용 위치 |
|
|
|----|----------|
|
|
| sirsoft-ecommerce.admin.product.xxx | file.json:line |
|
|
| ... | ... |
|
|
|
|
#### 공통 키 누락 (common.*)
|
|
| 키 | 사용 위치 |
|
|
|----|----------|
|
|
| common.xxx | file.json:line |
|
|
| ... | ... |
|
|
|
|
### 미사용 키 (참고)
|
|
- 총 미사용: XX개
|
|
| 키 | 위치 |
|
|
|----|------|
|
|
| sirsoft-ecommerce.xxx.unused | ko.json |
|
|
```
|
|
|
|
### 5.2 키 생성 템플릿 제공
|
|
|
|
누락된 키에 대한 JSON 템플릿 생성:
|
|
|
|
```json
|
|
// ko.json에 추가할 키
|
|
{
|
|
"admin": {
|
|
"product": {
|
|
"missing_key_1": "[한국어 번역 필요]",
|
|
"missing_key_2": "[한국어 번역 필요]"
|
|
}
|
|
}
|
|
}
|
|
|
|
// en.json에 추가할 키
|
|
{
|
|
"admin": {
|
|
"product": {
|
|
"missing_key_1": "[English translation needed]",
|
|
"missing_key_2": "[English translation needed]"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## 6단계: 추출 스크립트 (참고)
|
|
|
|
### Node.js 추출 스크립트 예시
|
|
|
|
```javascript
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
// 디렉토리 내 모든 JSON 파일 찾기
|
|
function findJsonFiles(dir, files = []) {
|
|
const items = fs.readdirSync(dir);
|
|
for (const item of items) {
|
|
const fullPath = path.join(dir, item);
|
|
if (fs.statSync(fullPath).isDirectory()) {
|
|
findJsonFiles(fullPath, files);
|
|
} else if (item.endsWith('.json')) {
|
|
files.push(fullPath);
|
|
}
|
|
}
|
|
return files;
|
|
}
|
|
|
|
// $t: 키 추출
|
|
function extractI18nKeys(content) {
|
|
const regex = /\$t:(?:defer:)?([a-zA-Z][a-zA-Z0-9_.-]*(?:\.[a-zA-Z0-9_-]+)+)/g;
|
|
const keys = new Set();
|
|
let match;
|
|
while ((match = regex.exec(content)) !== null) {
|
|
keys.add(match[1]);
|
|
}
|
|
return keys;
|
|
}
|
|
|
|
// JSON에서 키 경로 추출
|
|
function extractExistingKeys(obj, prefix = '', namespace = '') {
|
|
const keys = new Set();
|
|
for (const [key, value] of Object.entries(obj)) {
|
|
const path = prefix ? `${prefix}.${key}` : key;
|
|
const fullPath = namespace ? `${namespace}.${path}` : path;
|
|
if (typeof value === 'object' && value !== null) {
|
|
const childKeys = extractExistingKeys(value, path, namespace);
|
|
childKeys.forEach(k => keys.add(k));
|
|
} else {
|
|
keys.add(fullPath);
|
|
}
|
|
}
|
|
return keys;
|
|
}
|
|
|
|
// 메인 실행
|
|
const layoutDir = process.argv[2] || 'modules/sirsoft-ecommerce/resources/layouts';
|
|
const langDir = process.argv[3] || 'modules/sirsoft-ecommerce/resources/lang';
|
|
const namespace = process.argv[4] || 'sirsoft-ecommerce';
|
|
|
|
// 레이아웃에서 사용된 키 추출
|
|
const layoutFiles = findJsonFiles(layoutDir);
|
|
const usedKeys = new Set();
|
|
for (const file of layoutFiles) {
|
|
const content = fs.readFileSync(file, 'utf-8');
|
|
const keys = extractI18nKeys(content);
|
|
keys.forEach(k => usedKeys.add(k));
|
|
}
|
|
|
|
// 언어 파일에서 존재하는 키 추출
|
|
const koJson = JSON.parse(fs.readFileSync(path.join(langDir, 'ko.json'), 'utf-8'));
|
|
const existingKeys = extractExistingKeys(koJson, '', namespace);
|
|
|
|
// 비교
|
|
const missingKeys = [...usedKeys].filter(k => !existingKeys.has(k));
|
|
const unusedKeys = [...existingKeys].filter(k => !usedKeys.has(k));
|
|
|
|
console.log('=== 다국어 키 추출 결과 ===');
|
|
console.log(`사용된 키: ${usedKeys.size}개`);
|
|
console.log(`존재하는 키: ${existingKeys.size}개`);
|
|
console.log(`누락된 키: ${missingKeys.length}개`);
|
|
console.log(`미사용 키: ${unusedKeys.length}개`);
|
|
|
|
if (missingKeys.length > 0) {
|
|
console.log('\n=== 누락된 키 목록 ===');
|
|
missingKeys.sort().forEach(k => console.log(k));
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 핵심 원칙
|
|
|
|
```text
|
|
⚠️ CRITICAL:
|
|
- 모든 $t: 패턴 추출 (defer 포함)
|
|
- 모듈 네임스페이스와 공통 키 모두 추출
|
|
- 모듈 레이아웃: $t:키에 모듈 식별자 접두사 필수 ($t:sirsoft-ecommerce.xxx)
|
|
- _bundled 디렉토리 레이아웃도 추출 대상에 포함
|
|
- 정확한 키 경로 비교 (중첩 객체 고려)
|
|
- 누락 키에 대한 실용적인 템플릿 제공
|
|
- ko.json과 en.json 모두 검사
|
|
```
|
|
|
|
---
|
|
|
|
## 사용 예시
|
|
|
|
```bash
|
|
# 모듈 레이아웃 키 추출
|
|
/extract-i18n-keys modules/sirsoft-ecommerce/resources/layouts
|
|
|
|
# 특정 레이아웃 파일만 추출
|
|
/extract-i18n-keys modules/sirsoft-ecommerce/resources/layouts/admin/admin_ecommerce_product_form.json
|
|
|
|
# 템플릿 레이아웃 키 추출
|
|
/extract-i18n-keys templates/sirsoft-admin_basic/layouts
|
|
```
|