# Custom Exception 다국어 처리 > 이 문서는 G7에서 Custom Exception 클래스의 다국어 처리 방법을 설명합니다. --- ## TL;DR (5초 요약) ```text 1. 예외 메시지 하드코딩 금지 → __() 함수 필수 2. 메시지 위치: lang/ko/exceptions.php, lang/en/exceptions.php 3. 파라미터 치환: __('exceptions.key', ['param' => $value]) 4. 코어 예외: exceptions.template_engine.* 형식 5. 모듈 예외: vendor-module::exceptions.* 형식 ``` --- ## 목차 1. [핵심 원칙](#핵심-원칙) 2. [다국어 파일 위치 및 구조](#다국어-파일-위치-및-구조) 3. [파라미터 치환 패턴](#파라미터-치환-패턴) 4. [템플릿 엔진 Custom Exception 예시](#템플릿-엔진-custom-exception-예시) 5. [Custom Exception 개발 체크리스트](#custom-exception-개발-체크리스트) 6. [관련 문서](#관련-문서) --- ## 핵심 원칙 ``` 필수: __() 함수 사용 (예외 메시지 하드코딩 금지) 필수: __() 함수를 사용한 다국어 처리 ``` ### 필수 규칙 - **모든 예외 메시지는 다국어 파일에 정의**: `/lang/ko/exceptions.php`, `/lang/en/exceptions.php` - **Exception 생성자에서 __() 함수 사용**: 하드코딩된 문자열 사용 금지 - **파라미터 치환 지원**: `:trace`, `:max`, `:id` 등의 동적 값 지원 - **일관성 유지**: 모든 커스텀 예외가 동일한 패턴 사용 --- ## 다국어 파일 위치 및 구조 ### 파일 위치 ``` /lang/ko/exceptions.php # 한국어 예외 메시지 /lang/en/exceptions.php # 영어 예외 메시지 ``` ### 파일 구조 예시 ```php // /lang/ko/exceptions.php return [ 'circular_reference' => '레이아웃 순환 참조 감지: :trace', 'max_depth_exceeded' => '레이아웃 중첩 깊이가 최대 허용 깊이(:max)를 초과했습니다.', 'resource_not_found' => ':resource를 찾을 수 없습니다.', ]; // /lang/en/exceptions.php return [ 'circular_reference' => 'Layout circular reference detected: :trace', 'max_depth_exceeded' => 'Layout nesting depth exceeds maximum allowed depth (:max).', 'resource_not_found' => ':resource not found.', ]; ``` ### 중첩 구조 (네임스페이스 그룹화) ```php // /lang/ko/exceptions.php return [ 'template' => [ 'circular_reference' => '레이아웃 순환 참조 감지: :trace', 'max_depth_exceeded' => '레이아웃 중첩 깊이(:current)가 최대 허용 깊이(:max)를 초과했습니다.', 'template_not_found' => '템플릿을 찾을 수 없습니다: :identifier', 'layout_not_found' => '레이아웃을 찾을 수 없습니다: :layout_name', 'component_not_found' => '컴포넌트를 찾을 수 없습니다: :component_name', 'invalid_layout_structure' => '유효하지 않은 레이아웃 구조입니다.', ], ]; // /lang/en/exceptions.php return [ 'template' => [ 'circular_reference' => 'Layout circular reference detected: :trace', 'max_depth_exceeded' => 'Layout nesting depth (:current) exceeds maximum allowed depth (:max).', 'template_not_found' => 'Template not found: :identifier', 'layout_not_found' => 'Layout not found: :layout_name', 'component_not_found' => 'Component not found: :component_name', 'invalid_layout_structure' => 'Invalid layout structure.', ], ]; ``` --- ## 파라미터 치환 패턴 ### 잘못된 예시 (DON'T) ```php // ❌ 하드코딩된 예외 메시지 - 금지 class CircularReferenceException extends Exception { public function __construct(array $stack, string $currentLayout) { $stackTrace = implode(' → ', $stack) . " → {$currentLayout}"; $message = "레이아웃 순환 참조 감지: {$stackTrace}"; // 한국어만 지원, 다국어 불가 parent::__construct($message); } } ``` ### 올바른 예시 (DO) ```php // ✅ 다국어 함수 사용 (파라미터 치환) class CircularReferenceException extends Exception { private array $stack; public function __construct(array $stack, string $currentLayout) { $this->stack = $stack; // ✅ 다국어 함수 사용 (파라미터 치환) $stackTrace = implode(' → ', $stack) . " → {$currentLayout}"; $message = __('exceptions.circular_reference', ['trace' => $stackTrace]); parent::__construct($message); } public function getStack(): array { return $this->stack; } } ``` ### 다중 파라미터 처리 ```php class MaxDepthExceededException extends Exception { public function __construct(int $currentDepth, int $maxDepth) { // ✅ 다국어 함수 사용 (다중 파라미터) $message = __('exceptions.max_depth_exceeded', [ 'current' => $currentDepth, 'max' => $maxDepth ]); parent::__construct($message); } } ``` --- ## 템플릿 엔진 Custom Exception 예시 ### CircularReferenceException (레이아웃 순환 참조) 템플릿 레이아웃 상속 시 순환 참조가 발생하면 이 예외를 발생시킵니다. ```php stack = $stack; // ✅ 다국어 함수 사용 $stackTrace = implode(' → ', $stack) . " → {$currentLayout}"; $message = __('exceptions.template.circular_reference', ['trace' => $stackTrace]); parent::__construct($message); } /** * 순환 참조 스택 반환 */ public function getStack(): array { return $this->stack; } } ``` ### MaxDepthExceededException (레이아웃 깊이 초과) 레이아웃 상속 깊이가 최대 허용 깊이(10)를 초과하면 이 예외를 발생시킵니다. ```php currentDepth = $currentDepth; $this->maxDepth = $maxDepth; // ✅ 다국어 함수 사용 (다중 파라미터) $message = __('exceptions.template.max_depth_exceeded', [ 'current' => $currentDepth, 'max' => $maxDepth ]); parent::__construct($message); } /** * 현재 깊이 반환 */ public function getCurrentDepth(): int { return $this->currentDepth; } /** * 최대 허용 깊이 반환 */ public function getMaxDepth(): int { return $this->maxDepth; } } ``` ### Service에서 사용 예시 (LayoutService) ```php self::MAX_DEPTH) { throw new MaxDepthExceededException($depth, self::MAX_DEPTH); } // 재귀적으로 레이아웃 병합 // ... } } ``` --- ## Custom Exception 개발 체크리스트 새로운 Custom Exception을 개발할 때 다음 항목을 확인하세요: - [ ] `/lang/ko/exceptions.php`에 한국어 메시지 추가 - [ ] `/lang/en/exceptions.php`에 영어 메시지 추가 - [ ] Exception 생성자에서 모든 메시지는 `__()` 함수 사용 - [ ] 동적 값은 파라미터 배열로 전달 (예: `['trace' => $stackTrace]`) - [ ] 두 언어 모두에서 테스트 수행 - [ ] 예외 메시지가 사용자에게 노출될 경우 보안 정보 포함 금지 ### 새 Exception 추가 절차 1. **다국어 키 정의**: 적절한 네임스페이스로 그룹화 2. **Exception 클래스 생성**: `__()` 함수로 메시지 생성 3. **필요한 속성 저장**: 디버깅이나 로깅에 필요한 값 보관 4. **getter 메서드 제공**: 저장된 속성에 접근할 수 있도록 제공 5. **테스트 작성**: 두 언어 환경에서 메시지 확인 --- ## 관련 문서 - [validation.md](./validation.md) - Custom Rule 다국어 처리 - [index.md](./index.md) - 백엔드 가이드 인덱스