Add extract configuration and enhance untranslated extraction functionality
This commit is contained in:
10
.claude/settings.local.json
Normal file
10
.claude/settings.local.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Read(//d/Work/WorldStalker/**)",
|
||||
"Bash(python ds_l10n.py:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
}
|
||||
}
|
||||
13
config.yaml
13
config.yaml
@ -143,6 +143,19 @@ logging:
|
||||
# 진행률 표시
|
||||
show_progress: true
|
||||
|
||||
# ============================================================================
|
||||
# 미번역 추출 설정 (Extract)
|
||||
# ============================================================================
|
||||
extract:
|
||||
# 모든 대상 언어 검사 (false면 en만 검사)
|
||||
check_all_languages: false
|
||||
|
||||
# fuzzy 플래그 항목도 포함 (원본 변경으로 리뷰 필요한 항목)
|
||||
include_fuzzy: true
|
||||
|
||||
# 언어별 개별 파일로 추출 (false면 통합 파일)
|
||||
separate_files: true
|
||||
|
||||
# ============================================================================
|
||||
# 워크플로우 설정 (Workflow)
|
||||
# ============================================================================
|
||||
|
||||
126
ds_l10n.py
126
ds_l10n.py
@ -32,6 +32,24 @@ def command_extract(args, config, logger):
|
||||
"""미번역 항목 추출"""
|
||||
logger.section('미번역 항목 추출', Icons.SEARCH)
|
||||
|
||||
# extract 설정
|
||||
check_all_languages = config.get('extract.check_all_languages', False)
|
||||
include_fuzzy = config.get('extract.include_fuzzy', False)
|
||||
separate_files = config.get('extract.separate_files', True)
|
||||
|
||||
# CLI 옵션으로 설정 오버라이드
|
||||
if hasattr(args, 'include_fuzzy') and args.include_fuzzy is not None:
|
||||
include_fuzzy = args.include_fuzzy
|
||||
if hasattr(args, 'all_languages') and args.all_languages:
|
||||
check_all_languages = True
|
||||
|
||||
# 출력 디렉토리
|
||||
output_dir = config.get_path('paths.output_dir')
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
timestamp = get_timestamp()
|
||||
po_handler = POHandler(config.data, logger)
|
||||
|
||||
# GUI 모드
|
||||
if args.gui:
|
||||
logger.info('GUI 모드로 실행합니다...')
|
||||
@ -53,35 +71,105 @@ def command_extract(args, config, logger):
|
||||
|
||||
po_path = Path(po_path)
|
||||
|
||||
else:
|
||||
# CLI 모드: config에서 경로 가져오기
|
||||
unreal_loc = config.get_path('paths.unreal_localization')
|
||||
source_lang = config.get('languages.source', 'ko')
|
||||
po_path = unreal_loc / source_lang / config.get('files.po_filename', 'LocalExport.po')
|
||||
|
||||
if not po_path.exists():
|
||||
logger.error(f'PO 파일을 찾을 수 없습니다: {po_path}')
|
||||
return False
|
||||
|
||||
# 출력 파일 경로
|
||||
output_dir = config.get_path('paths.output_dir')
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
timestamp = get_timestamp()
|
||||
pattern = config.get('files.untranslated_pattern', 'untranslated_{timestamp}.tsv')
|
||||
output_filename = pattern.format(timestamp=timestamp)
|
||||
output_path = output_dir / output_filename
|
||||
|
||||
# 추출 실행
|
||||
po_handler = POHandler(config.data, logger)
|
||||
count = po_handler.extract_untranslated(po_path, output_path)
|
||||
count = po_handler.extract_untranslated(po_path, output_path, include_fuzzy)
|
||||
|
||||
if count > 0:
|
||||
logger.success(f'\n✅ 미번역 항목 {count}건 추출 완료')
|
||||
logger.info(f'📄 출력 파일: {output_path}')
|
||||
else:
|
||||
logger.success(f'\n✅ 모든 텍스트가 번역되어 있습니다!')
|
||||
logger.info('미번역 항목이 없습니다. 번역 작업이 완료된 상태입니다.')
|
||||
|
||||
return True
|
||||
|
||||
# CLI 모드
|
||||
unreal_loc = config.get_path('paths.unreal_localization')
|
||||
|
||||
if not unreal_loc.exists():
|
||||
logger.error(f'언리얼 현지화 폴더를 찾을 수 없습니다: {unreal_loc}')
|
||||
return False
|
||||
|
||||
logger.info(f'언리얼 현지화 폴더: {unreal_loc}')
|
||||
logger.info(f'fuzzy 항목 포함: {"예" if include_fuzzy else "아니오"}')
|
||||
|
||||
# 검사할 언어 결정
|
||||
if check_all_languages:
|
||||
# 모든 대상 언어 검사
|
||||
target_langs = config.get('languages.targets', [])
|
||||
if not target_langs:
|
||||
logger.error('config.yaml에 대상 언어(languages.targets)가 정의되지 않았습니다.')
|
||||
return False
|
||||
|
||||
logger.info(f'대상 언어: {", ".join(target_langs)}')
|
||||
else:
|
||||
# en만 검사 (기본 동작)
|
||||
target_langs = ['en']
|
||||
logger.info(f'검사 언어: en')
|
||||
|
||||
# 언어별로 미번역 추출
|
||||
total_extracted = 0
|
||||
extracted_files = []
|
||||
|
||||
for lang in target_langs:
|
||||
po_path = unreal_loc / lang / config.get('files.po_filename', 'LocalExport.po')
|
||||
|
||||
if not po_path.exists():
|
||||
logger.warning(f' ⚠️ {lang}: PO 파일을 찾을 수 없음 - {po_path}')
|
||||
continue
|
||||
|
||||
# 출력 파일 경로
|
||||
if check_all_languages and separate_files:
|
||||
# 모든 언어 검사 시: 언어별 개별 파일
|
||||
output_filename = f'untranslated_{lang}_{timestamp}.tsv'
|
||||
else:
|
||||
# en만 검사 시: 단일 파일 (언어 코드 생략)
|
||||
pattern = config.get('files.untranslated_pattern', 'untranslated_{timestamp}.tsv')
|
||||
output_filename = pattern.format(timestamp=timestamp)
|
||||
|
||||
output_path = output_dir / output_filename
|
||||
|
||||
# 모든 언어 검사 시에만 언어별로 구분하여 표시
|
||||
if check_all_languages:
|
||||
logger.separator()
|
||||
logger.info(f'🔍 {lang} 처리 중...')
|
||||
|
||||
# 추출 실행
|
||||
count = po_handler.extract_untranslated(po_path, output_path, include_fuzzy)
|
||||
|
||||
if count > 0:
|
||||
total_extracted += count
|
||||
extracted_files.append((lang, output_path, count))
|
||||
if check_all_languages:
|
||||
logger.success(f' ✅ {lang}: {count}건 추출')
|
||||
else:
|
||||
if check_all_languages:
|
||||
logger.success(f' ✅ {lang}: 모든 번역 완료')
|
||||
|
||||
# 최종 결과
|
||||
logger.separator()
|
||||
|
||||
if total_extracted > 0:
|
||||
if check_all_languages:
|
||||
# 모든 언어 검사: 언어별 상세 표시
|
||||
logger.success(f'\n✅ 총 {total_extracted}건의 미번역 항목 추출 완료')
|
||||
logger.info('\n📄 생성된 파일:')
|
||||
for lang, file_path, count in extracted_files:
|
||||
logger.info(f' - {file_path.name} ({lang}: {count}건)')
|
||||
else:
|
||||
# en만 검사: 간단한 메시지
|
||||
logger.success(f'\n✅ 미번역 항목 {total_extracted}건 추출 완료')
|
||||
logger.info(f'📄 출력 파일: {extracted_files[0][1]}')
|
||||
else:
|
||||
if check_all_languages:
|
||||
logger.success(f'\n✅ 모든 언어의 번역이 완료되어 있습니다!')
|
||||
else:
|
||||
logger.success(f'\n✅ 모든 텍스트가 번역되어 있습니다!')
|
||||
logger.info('미번역 항목이 없습니다.')
|
||||
|
||||
return True
|
||||
|
||||
@ -301,6 +389,10 @@ def main():
|
||||
# extract 명령어
|
||||
parser_extract = subparsers.add_parser('extract', help='미번역 항목 추출')
|
||||
parser_extract.add_argument('--gui', action='store_true', help='GUI 모드로 실행')
|
||||
parser_extract.add_argument('--include-fuzzy', action='store_true', dest='include_fuzzy',
|
||||
help='fuzzy 플래그 항목 포함 (원본 변경으로 리뷰 필요한 항목)')
|
||||
parser_extract.add_argument('--all-languages', action='store_true', dest='all_languages',
|
||||
help='모든 대상 언어 검사 (기본: en만 검사)')
|
||||
|
||||
# validate 명령어
|
||||
parser_validate = subparsers.add_parser('validate', help='번역 검증')
|
||||
|
||||
Binary file not shown.
@ -42,10 +42,15 @@ class POHandler:
|
||||
self.logger.error(f'PO 파일 로드 실패: {po_path} - {e}')
|
||||
return None
|
||||
|
||||
def extract_untranslated(self, po_path: Path, output_path: Path) -> int:
|
||||
def extract_untranslated(self, po_path: Path, output_path: Path, include_fuzzy: bool = False) -> int:
|
||||
"""
|
||||
미번역 항목 추출
|
||||
|
||||
Args:
|
||||
po_path: PO 파일 경로
|
||||
output_path: 출력 TSV 파일 경로
|
||||
include_fuzzy: fuzzy 플래그 항목 포함 여부 (원본 변경으로 리뷰 필요한 항목)
|
||||
|
||||
Returns:
|
||||
추출된 항목 개수
|
||||
"""
|
||||
@ -57,20 +62,37 @@ class POHandler:
|
||||
|
||||
# 전체 항목 및 미번역 항목 필터링
|
||||
total_entries = len([entry for entry in po if entry.msgid]) # msgid가 있는 항목만 카운트
|
||||
|
||||
# 미번역 항목: msgstr이 비어있는 항목
|
||||
untranslated = [entry for entry in po if not entry.msgstr.strip()]
|
||||
|
||||
if not untranslated:
|
||||
# fuzzy 항목: fuzzy 플래그가 있는 항목 (원본 변경으로 리뷰 필요)
|
||||
fuzzy_entries = []
|
||||
if include_fuzzy:
|
||||
fuzzy_entries = [entry for entry in po if 'fuzzy' in entry.flags and entry.msgstr.strip()]
|
||||
|
||||
# 통합 리스트
|
||||
all_entries = untranslated + fuzzy_entries
|
||||
|
||||
if not all_entries:
|
||||
translated_count = total_entries
|
||||
self.logger.info(f'전체 {total_entries}개 항목 중 {translated_count}개 번역 완료 (100%)')
|
||||
return 0
|
||||
|
||||
self.logger.info(f'전체 {total_entries}개 항목 중 미번역 {len(untranslated)}건 발견')
|
||||
# 통계 출력
|
||||
if include_fuzzy and fuzzy_entries:
|
||||
self.logger.info(f'전체 {total_entries}개 항목 중:')
|
||||
self.logger.info(f' - 미번역 항목: {len(untranslated)}건')
|
||||
self.logger.info(f' - 리뷰 필요 (fuzzy): {len(fuzzy_entries)}건')
|
||||
self.logger.info(f' - 총 추출 항목: {len(all_entries)}건')
|
||||
else:
|
||||
self.logger.info(f'전체 {total_entries}개 항목 중 미번역 {len(all_entries)}건 발견')
|
||||
|
||||
# TSV 파일로 저장
|
||||
self._save_to_tsv(untranslated, output_path)
|
||||
self._save_to_tsv(all_entries, output_path)
|
||||
|
||||
self.logger.success(f'미번역 항목 추출 완료: {output_path}')
|
||||
return len(untranslated)
|
||||
return len(all_entries)
|
||||
|
||||
def merge_to_csv(self, localization_root: Path, output_path: Path) -> int:
|
||||
"""
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
msgctxt SourceLocation ko en ja zh-Hans zh-Hant es-ES es-419 fr-FR de-DE ru-RU pt-BR pt-PT it-IT pl-PL tr-TR uk-UA vi-VN th
|
||||
,UITitleAdventurerGuild /Game/Blueprints/DataTable/DT_StringTable.DT_StringTable 모험가 길드 Advent. Guild 冒険家ギルド 冒险家公会 冒險家公會 Gremio Avent. Gremio Avent. Guilde Avent. Abenteurergilde Гильдия Авант. Guilda Avent. Guilda Avent. Gilda Avvent. Gildia Awant. Macera Loncası Гільдія Авант. Hội Thám Hiểm กิลด์ผู้ผจญภัย
|
||||
,UIReputationPointExpect /Game/Blueprints/DataTable/DT_StringTable.DT_StringTable 이번 시즌 추가 예정 점수 Points scheduled for this season 今シーズン追加予定点数 本赛季计划新增点数 本賽季計畫新增點數 Puntos programados para esta temporada Puntos programados para esta temporada Points prévus pour cette saison Für diese Saison geplante Punkte Заплановані очки на цей сезон Pontos programados para esta temporada Pontos previstos para esta época Punti previsti per questa stagione Punkty zaplanowane na ten sezon Bu sezon için planlanan puanlar Заплановані очки цього сезону Điểm dự kiến cho mùa này คะแนนที่กำหนดสำหรับซีซันนี้
|
||||
|
Reference in New Issue
Block a user