diff --git a/i18n/kr/docusaurus-plugin-content-docs/current/guides/examples/auth.md b/i18n/kr/docusaurus-plugin-content-docs/current/guides/examples/auth.md
index 60fe0d201..7fb1819ca 100644
--- a/i18n/kr/docusaurus-plugin-content-docs/current/guides/examples/auth.md
+++ b/i18n/kr/docusaurus-plugin-content-docs/current/guides/examples/auth.md
@@ -12,11 +12,11 @@ sidebar_position: 1
## 사용자 로그인 정보 수집 방법
-앱에서 사용자로부터 로그인 정보를 수집하는 방법을 알아보겠습니다. 만약에 OAuth를 사용하는 경우, OAuth 제공자의 로그인 페이지를 사용하여 [3단계](#how-to-store-the-token-for-authenticated-requests)로 바로 넘어갈 수 있습니다.
+앱에서 사용자로부터 로그인 정보를 수집하는 방법을 알아보겠습니다. 만약에 OAuth를 사용하는 경우, OAuth 제공자의 로그인 page를 사용하여 [3단계](#how-to-store-the-token-for-authenticated-requests)로 바로 넘어갈 수 있습니다.
-### 전용 로그인 페이지 만들기
+### 전용 로그인 page 만들기
-웹사이트에서 사용자 이름과 비밀번호를 입력하는 로그인 페이지를 제공하는 것이 일반적입니다. 이러한 페이지들은 구조가 단순하여 별도의 복잡한 분해 작업이 필요하지 않습니다. 다만, 로그인과 회원가입 양식은 외형이 비슷하기 때문에, 경우에 따라 두 양식을 하나의 페이지에서 통합하여 제공하기도 합니다.
+웹사이트에서 사용자 이름과 비밀번호를 입력하는 로그인 page를 제공하는 것이 일반적입니다. 이러한 page들은 구조가 단순하여 별도의 복잡한 분해 작업이 필요하지 않습니다. 다만, 로그인과 회원가입 양식은 외형이 비슷하기 때문에, 경우에 따라 두 양식을 하나의 page에서 통합하여 제공하기도 합니다.
- 📂 pages
- 📂 login
@@ -28,9 +28,9 @@ sidebar_position: 1
로그인과 회원가입 컴포넌트를 별도로 만들고, 필요에 따라 index 파일에서 export 할 수 있습니다. 이 컴포넌트들은 사용자로부터 로그인 정보을 입력받는 폼을 포함합니다.
-### 로그인 다이얼로그 만들기
+### 로그인 widget 만들기
-앱의 어디서나 사용할 수 있는 로그인 다이얼로그가 필요하다면, 이 다이얼로그를 재사용 가능한 위젯으로 만드는 것이 좋습니다. 이렇게 하면 불필요한 세분화를 피하면서도 어떤 페이지에서나 쉽게 로그인 다이얼로그를 띄울 수 있습니다.
+앱의 어디서나 사용할 수 있는 로그인 다이얼로그가 필요하다면, 이 다이얼로그를 재사용 가능한 widget으로 만드는 것이 좋습니다. 이렇게 하면 불필요한 세분화를 피하면서도 어떤 page에서나 쉽게 로그인 다이얼로그를 띄울 수 있습니다.
- 📂 widgets
- 📂 login-dialog
@@ -39,11 +39,11 @@ sidebar_position: 1
- 📄 index.ts
- other widgets…
-가이드 나머지 부분은 전용 페이지 방식에 대해 설명하고 있지만, 동일한 원칙을 로그인 다이얼로그에도 적용할 수 있습니다.
+가이드 나머지 부분은 전용 page 방식에 대해 설명하고 있지만, 동일한 원칙을 로그인 다이얼로그에도 적용할 수 있습니다.
### 클라이언트 측 검증
-특히 회원가입의 경우, 사용자가 입력한 내용에 문제가 있을 때 빠르게 피드백을 제공하기 위해 클라이언트 측 검증을 수행하는 것이 좋습니다. 이를 위해 로그인 페이지의 `model` 세그먼트에서 검증 로직을 구현할 수 있습니다. 예를 들어 JS/TS에서는 [Zod][ext-zod]와 같은 스키마 검증 라이브러리를 사용할 수 있습니다:
+특히 회원가입의 경우, 사용자가 입력한 내용에 문제가 있을 때 빠르게 피드백을 제공하기 위해 클라이언트 측 검증을 수행하는 것이 좋습니다. 이를 위해 로그인 page의 `model` segment에서 검증 로직을 구현할 수 있습니다. 예를 들어 JS/TS에서는 [Zod][ext-zod]와 같은 스키마 검증 라이브러리를 사용할 수 있습니다:
```ts title="pages/login/model/registration-schema.ts"
import { z } from "zod";
@@ -58,7 +58,7 @@ export const registrationData = z.object({
});
```
-그런 다음, ui 세그먼트에서 이 스키마를 사용하여 사용자 입력을 검증할 수 있습니다:
+그런 다음, ui segment에서 이 스키마를 사용하여 사용자 입력을 검증할 수 있습니다:
```tsx title="pages/login/ui/RegisterPage.tsx"
import { registrationData } from "../model/registration-schema";
@@ -90,11 +90,11 @@ export function RegisterPage() {
## 로그인 정보 전송 방법
-로그인 정보를 백엔드 서버로 전송하기 위한 요청 함수를 작성하세요. 이 함수는 상태 관리 라이브러리나 뮤테이션 라이브러리(예: TanStack Query)를 사용하여 호출할 수 있습니다.
+로그인 정보를 백엔드 서버로 전송하기 위한 요청 함수를 작성하세요. 이 함수는 상태 관리 라이브러리나 mutation 라이브러리(예: TanStack Query)를 사용하여 호출할 수 있습니다.
### 요청 함수 저장 위치
-이 요청 함수를 저장할 수 있는 위치는 크게 두 가지입니다: `shared/api` 또는 페이지의 `api` 세그먼트입니다.
+이 요청 함수를 저장할 수 있는 위치는 크게 두 가지입니다: `shared/api` 또는 page의 `api` segment입니다.
#### `shared/api`에 저장하기
@@ -108,7 +108,7 @@ export function RegisterPage() {
- 📄 client.ts
- 📄 index.ts
-`📄 client.ts` 파일은 요청을 수행하는 원시 함수(예: `fetch()`)에 대한 래퍼를 포함합니다. 이 래퍼는 백엔드의 기본 URL 설정, 헤더 설정, 데이터 직렬화 등을 처리합니다.
+`📄 client.ts` 파일은 요청을 수행하는 원시 함수(예: `fetch()`)에 대한 wrapper를 포함합니다. 이 wrapper는 백엔드의 기본 URL 설정, 헤더 설정, 데이터 직렬화 등을 처리합니다.
```ts title="shared/api/endpoints/login.ts"
import { POST } from "../client";
@@ -122,9 +122,9 @@ export function login({ email, password }: { email: string, password: string })
export { login } from "./endpoints/login";
```
-#### 페이지의 `api` 세그먼트에 저장하기
+#### page의 `api` segment에 저장하기
-로그인 요청이 특정 페이지에만 필요한 경우, 로그인 페이지의 `api` 세그먼트에 함수를 저장할 수 있습니다:
+로그인 요청이 특정 page에만 필요한 경우, 로그인 page의 `api` segment에 함수를 저장할 수 있습니다:
- 📂 pages
- 📂 login
@@ -143,15 +143,15 @@ export function login({ email, password }: { email: string, password: string })
}
```
-이 함수는 페이지의 공개 API에서 내보낼 필요가 없습니다. 로그인 요청이 다른 곳에서 필요할 가능성이 낮기 때문입니다.
+이 함수는 page의 공개 API에서 내보낼 필요가 없습니다. 로그인 요청이 다른 곳에서 필요할 가능성이 낮기 때문입니다.
### 이중 인증(2FA)
-앱이 이중 인증(2FA)을 지원하는 경우, 사용자가 일회용 비밀번호(OTP)를 입력할 수 있는 별도의 페이지로 이동해야 할 수 있습니다. 일반적으로 `POST /login` 요청은 사용자가 2FA를 활성화했음을 나타내는 플래그가 포함된 사용자 객체를 반환합니다. 이 플래그가 설정되면 사용자를 2FA 페이지로 리디렉션해야 합니다.
+앱이 이중 인증(2FA)을 지원하는 경우, 사용자가 일회용 비밀번호(OTP)를 입력할 수 있는 별도의 page로 이동해야 할 수 있습니다. 일반적으로 `POST /login` 요청은 사용자가 2FA를 활성화했음을 나타내는 플래그가 포함된 사용자 객체를 반환합니다. 이 플래그가 설정되면 사용자를 2FA page로 리디렉션해야 합니다.
-2FA 페이지는 로그인과 밀접하게 연관되어 있으므로 Pages 레이어의 `login` 슬라이스에 함께 저장하는 것이 좋습니다.
+2FA page는 로그인과 밀접하게 연관되어 있으므로 Pages layer의 `login` slice에 함께 저장하는 것이 좋습니다.
-이중 인증을 처리하기 위해서는 `login()` 함수와 유사한 또 다른 요청 함수가 필요할 것입니다. 이러한 함수들은 `Shared`나 로그인 페이지의 `api` 세그먼트에 함께 배치할 수 있습니다.
+이중 인증을 처리하기 위해서는 `login()` 함수와 유사한 또 다른 요청 함수가 필요할 것입니다. 이러한 함수들은 `Shared`나 로그인 page의 `api` segment에 함께 배치할 수 있습니다.
## 인증된 요청의 토큰 저장 방법 {#how-to-store-the-token-for-authenticated-requests}
@@ -163,7 +163,7 @@ export function login({ email, password }: { email: string, password: string })
### Shared에 저장하기
-`shared/api`에 저장하는 접근 방식은 API 클라이언트와 잘 맞아떨어집니다. 인증이 필요한 다른 요청 함수에서 이 토큰을 쉽게 사용할 수 있기 때문입니다. API 클라이언트에서 반응형 스토어나 모듈 수준 변수를 사용해 토큰을 저장하고, `login()/logout()` 함수에서 해당 상태를 업데이트할 수 있습니다.
+`shared/api`에 저장하는 접근 방식은 API 클라이언트와 잘 맞아떨어집니다. 인증이 필요한 다른 요청 함수에서 이 토큰을 쉽게 사용할 수 있기 때문입니다. API 클라이언트에서 반응형 store나 module 수준 변수를 사용해 토큰을 저장하고, `login()/logout()` 함수에서 해당 상태를 업데이트할 수 있습니다.
토큰 자동 갱신은 API 클라이언트에서 미들웨어 형태로 구현할 수 있습니다. 모든 요청마다 실행되며, 아래와 같은 방식으로 동작합니다:
@@ -177,7 +177,7 @@ export function login({ email, password }: { email: string, password: string })
### Entities에 저장하기
-FSD 프로젝트에서는 사용자 엔티티 또는 현재 사용자 엔티티를 사용하는 것이 일반적입니다. 두 엔티티는 같은 것을 가리킬 수도 있습니다.
+FSD 프로젝트에서는 user entity 또는 current user entity를 사용하는 것이 일반적입니다. 두 entity는 같은 것을 가리킬 수도 있습니다.
:::note
@@ -185,41 +185,41 @@ FSD 프로젝트에서는 사용자 엔티티 또는 현재 사용자 엔티티
:::
-User 엔티티에 토큰을 저장하려면 `model` 세그먼트에 반응형 스토어를 생성해야 합니다. 이 스토어는 토큰과 사용자 객체를 모두 포함할 수 있습니다.
+User entity에 토큰을 저장하려면 `model` segment에 reactive store를 생성해야 합니다. 이 store는 토큰과 user 객체를 모두 포함할 수 있습니다.
-API 클라이언트는 일반적으로 `shared/api` 정의되거나 엔티티 전체에 분산되어 있습니다. 따라서 주요 과제는 레이어의 임포트 규칙([import rule on layers][import-rule-on-layers])을 위반하지 않으면서 다른 요청에서도 토큰을 사용할 수 있도록 하는 것입니다.
+API 클라이언트는 일반적으로 `shared/api` 정의되거나 entity 전체에 분산되어 있습니다. 따라서 주요 과제는 layer의 임포트 규칙([import rule on layers][import-rule-on-layers])을 위반하지 않으면서 다른 요청에서도 토큰을 사용할 수 있도록 하는 것입니다.
-> 레이어 규칙: 슬라이스의 모듈은 자기보다 낮은 레이어에 위치한 다른 슬라이스만 임포트할 수 있습니다.
+> Layer 규칙: slice의 module은 자기보다 낮은 layer에 위치한 다른 slice만 import할 수 있습니다.
이 문제를 해결하기 위한 몇 가지 방법은 다음과 같습니다:
1. **요청 시마다 토큰 수동 전달**
이 방법은 가장 간단하지만, 번거롭고 타입 안전성이 보장되지 않으면 실수가 발생할 가능성이 큽니다. 또한 Shared의 API 클라이언트에 미들웨어 패턴을 적용하기 어렵습니다.
-2. **앱 전역에서 글로벌 스토어로 토큰 관리**
- 토큰을 context나 `localStorage`에 저장하고, `shared/api`에 토큰 접근 키를 보관합니다. 토큰의 반응형 저장소는 User 엔터티에서 내보내며, 필요한 경우 context Provider는 App 레이어에서 설정합니다. 이 방법은 API 클라이언트 설계를 유연하게 만들지만, 상위 레이어에 context 제공이 필요하다는 암묵적인 의존성을 발생시킵니다. 따라서 context나 `localStorage`가 제대로 설정되지 않았을 경우, 유용한 오류 메시지를 제공하는 것이 좋습니다.
+2. **앱 전역에서 글로벌 store로 토큰 관리**
+ 토큰을 context나 `localStorage`에 저장하고, `shared/api`에 토큰 접근 키를 보관합니다. 토큰의 reactive store는 User entity에서 내보내며, 필요한 경우 context Provider는 App layer에서 설정합니다. 이 방법은 API 클라이언트 설계를 유연하게 만들지만, 상위 layer에 context 제공이 필요하다는 암묵적인 의존성을 발생시킵니다. 따라서 context나 `localStorage`가 제대로 설정되지 않았을 경우, 유용한 오류 메시지를 제공하는 것이 좋습니다.
3. **토큰 변경 시 API 클라이언트 업데이트**
- 반응형 스토어를 활용해 엔티티의 스토어가 변경될 때마다 API 클라이언트의 토큰 스토어를 업데이트하는 구독(subscribe)을 생성할 수 있습니다. 이 방법은 상위 계층에 암묵적인 의존성을 만든다는 점에서는 이전 해결책과 비슷하지만, 이 방법은 더 "명령형(push)" 접근이고, 이전 방법은 더 "선언형(pull)" 접근입니다.
+ reactive store를 활용해 entity의 store가 변경될 때마다 API 클라이언트의 토큰 store를 업데이트하는 구독(subscribe)을 생성할 수 있습니다. 이 방법은 상위 layer에 암묵적인 의존성을 만든다는 점에서는 이전 해결책과 비슷하지만, 이 방법은 더 "명령형(push)" 접근이고, 이전 방법은 더 "선언형(pull)" 접근입니다.
-엔티티의 `model`에 토큰을 저장하여 문제를 해결하면, 토큰 관리와 관련된 더 많은 비즈니스 로직을 추가할 수 있습니다. 예를 들어, `model` 세그먼트에 토큰 만료 시 갱신하는 로직을 추가하거나, 일정 시간이 지나면 토큰을 무효화하는 로직을 포함할 수 있습니다.
-백엔드에 요청을 보내야 하는 경우에는 User 엔티티의 api 세그먼트나 `shared/api`를 사용할 수 있습니다.
+entity의 `model` segment에 토큰을 저장하여 문제를 해결하면, 토큰 관리와 관련된 더 많은 비즈니스 로직을 추가할 수 있습니다. 예를 들어, `model` segment에 토큰 만료 시 갱신하는 로직을 추가하거나, 일정 시간이 지나면 토큰을 무효화하는 로직을 포함할 수 있습니다.
+백엔드에 요청을 보내야 하는 경우에는 User entity의 api segment나 `shared/api`를 사용할 수 있습니다.
### Pages/Widgets에 저장하기 (권장하지 않음)
-애플리케이션 전역에 적용되는 상태(예: 액세스 토큰)를 페이지나 위젯에 저장하는 것은 권장되지 않습니다. 예를 들어, 로그인 페이지의 `model` 세그먼트에 토큰 스토어를 배치하는 대신, 이 아티클에서 제시한 처음 두 해결책인 Shared나 Entities를 사용하는 것이 권장됩니다.
+애플리케이션 전역에 적용되는 상태(예: 액세스 토큰)를 page나 widget에 저장하는 것은 권장되지 않습니다. 예를 들어, 로그인 page의 `model` segment에 토큰 store를 배치하는 대신, 이 아티클에서 제시한 처음 두 해결책인 Shared나 Entities를 사용하는 것이 권장됩니다.
## 로그아웃 및 토큰 무효화
-로그아웃 기능은 애플리케이션에서 중요한 기능이지만, 이를 위한 별도의 페이지는 없는 경우가 많습니다. 이 기능은 백엔드에 인증된 요청을 보내고, 토큰 스토어를 업데이트하는 작업으로 구성됩니다.
+로그아웃 기능은 애플리케이션에서 중요한 기능이지만, 이를 위한 별도의 page는 없는 경우가 많습니다. 이 기능은 백엔드에 인증된 요청을 보내고, 토큰 store를 업데이트하는 작업으로 구성됩니다.
-모든 요청을 `shared/api`에 보관했다면, 로그인 함수 근처에 로그아웃 요청 함수를 두는 것이 좋습니다. 그렇지 않은 경우, 로그아웃 버튼이 있는 위치 근처에 로그아웃 요청 함수를 배치할 수 있습니다. 예를 들어, 모든 페이지에 나타나는 헤더 위젯에 로그아웃 링크가 있다면, 해당 요청을 그 위젯의 `api` 세그먼트에 배치하는 것이 좋습니다.
+모든 요청을 `shared/api`에 보관했다면, 로그인 함수 근처에 로그아웃 요청 함수를 두는 것이 좋습니다. 그렇지 않은 경우, 로그아웃 버튼이 있는 위치 근처에 로그아웃 요청 함수를 배치할 수 있습니다. 예를 들어, 모든 page에 나타나는 header widget에 로그아웃 링크가 있다면, 해당 요청을 그 widget의 `api` segment에 배치하는 것이 좋습니다.
-토큰 스토어에 대한 업데이트는 로그아웃 버튼이 위치한 곳(예: 헤더 위젯)에서 트리거되어야 합니다. 이 요청과 스토어 업데이트를 해당 위젯의 `model` 세그먼트에서 결합할 수 있습니다.
+토큰 store에 대한 업데이트는 로그아웃 버튼이 위치한 곳(예: header widget)에서 트리거되어야 합니다. 이 요청과 store 업데이트를 해당 widget의 `model` segment에서 결합할 수 있습니다.
### 자동 로그아웃
-로그아웃 요청 실패나 로그인 토큰 갱신 실패 시를 대비해 안전장치를 마련하는 것도 중요합니다. 이 두 경우 모두 토큰 스토어를 비워야 합니다. 토큰을 Entities에 저장하는 경우, 이 로직은 `model` 세그먼트에 배치할 수 있습니다. 토큰을 Shared에 저장하는 경우, 이 로직을 `shared/api`에 포함하면 세그먼트가 너무 복잡해질 수 있습니다. 따라서 토큰 관리 로직을 별도의 세그먼트(예: `shared/auth`)로 분리하는 것도 고려해볼 만합니다.
+로그아웃 요청 실패나 로그인 토큰 갱신 실패 시를 대비해 안전장치를 마련하는 것도 중요합니다. 이 두 경우 모두 토큰 store를 비워야 합니다. 토큰을 Entities에 저장하는 경우, 이 로직은 `model` segment에 배치할 수 있습니다. 토큰을 Shared에 저장하는 경우, 이 로직을 `shared/api`에 포함하면 segment가 너무 복잡해질 수 있습니다. 따라서 토큰 관리 로직을 별도의 segment(예: `shared/auth`)로 분리하는 것도 고려해볼 만합니다.
[tutorial-authentication]: /docs/get-started/tutorial#authentication
[import-rule-on-layers]: /docs/reference/layers#import-rule-on-layers
[ext-remix]: https://remix.run
-[ext-zod]: https://zod.dev
+[ext-zod]: https://zod.dev
\ No newline at end of file
diff --git a/i18n/kr/docusaurus-plugin-content-docs/current/guides/examples/page-layout.md b/i18n/kr/docusaurus-plugin-content-docs/current/guides/examples/page-layout.md
index df57fa83f..fc23d4340 100644
--- a/i18n/kr/docusaurus-plugin-content-docs/current/guides/examples/page-layout.md
+++ b/i18n/kr/docusaurus-plugin-content-docs/current/guides/examples/page-layout.md
@@ -4,7 +4,7 @@ sidebar_position: 3
# Page layouts
-이 가이드는 여러 페이지가 같은 기본 구조를 공유하고, 주요 내용만 다른 경우 사용할 수 있는 _페이지 레이아웃_ 에 대해 설명합니다.
+이 가이드는 여러 page가 같은 기본 구조를 공유하고, 주요 내용만 다른 경우 사용할 수 있는 _page layout_ 에 대해 설명합니다.
:::info
@@ -14,7 +14,7 @@ sidebar_position: 3
## 간단한 레이아웃
-간단한 레이아웃 예시로 설명 해 보겠습니다. 이 페이지는 사이트 내비게이션이 포함된 헤더, 두 개의 사이드바, 외부 링크가 포함된 푸터로 구성되어 있습니다. 복잡한 비즈니스 로직은 없으며, 동적인 부분은 사이드바와 헤더 오른쪽에 있는 테마 전환 버튼뿐입니다. 이러한 레이아웃은 shared/ui 또는 app/layouts에 포함시킬 수 있으며, props를 통해 전달받은 사이드바 콘텐츠를 표시합니다.
+간단한 layout 예시로 설명 해 보겠습니다. 이 page는 사이트 내비게이션이 포함된 헤더, 두 개의 사이드바, 외부 링크가 포함된 푸터로 구성되어 있습니다. 복잡한 비즈니스 로직은 없으며, 동적인 부분은 사이드바와 헤더 오른쪽에 있는 테마 전환 버튼뿐입니다. 이러한 layout은 shared/ui 또는 app/layouts에 포함시킬 수 있으며, props를 통해 전달받은 사이드바 콘텐츠를 표시합니다.
```tsx title="shared/ui/layout/Layout.tsx"
import { Link, Outlet } from "react-router-dom";
@@ -74,26 +74,26 @@ export function useThemeSwitcher() {
상황에 따라 layout에 특정 비즈니스 로직을 추가하고 싶을 때가 있습니다. 특히 [React Router][ext-react-router]와 같은 라우터를 사용해 깊이 중첩된 경로를 다룰 때 이러한 요구가 발생합니다. 이러한 경우 layout을 shared나 widgets 폴더에 두는 것이 어려울 수 있습니다. 이는 [layer에 대한 import 규칙][import-rule-on-layers] 때문입니다:
-> slice의 module은 자신보다 하위 layers에 위치한 다른 slice만 import할 수 있습니다.
+> slice의 module은 자신보다 하위 layer에 위치한 다른 slice만 import할 수 있습니다.
-이 문제가 정말 중요한지 먼저 고려해 봐야 합니다. 레이아웃이 _정말로 필요한가요?_ 그리고 그 레이아웃이 _정말로 widget이어야 할까요?_ 만약 해당 비즈니스 로직이 2-3개의 페이지에서만 사용되고, 레이아웃이 그 widget을 감싸는 역할이라면, 다음 두 가지 방법을 고려해 보세요:
+이 문제가 정말 중요한지 먼저 고려해 봐야 합니다. layout이 _정말로 필요한가요?_ 그리고 그 layout이 _정말로 widget이어야 할까요?_ 만약 해당 비즈니스 로직이 2-3개의 page에서만 사용되고, layout이 그 widget을 감싸는 역할이라면, 다음 두 가지 방법을 고려해 보세요:
-1. **App 레이어에서 인라인으로 레이아웃 작성하기**
- App 레이어에서 직접 레이아웃을 정의하는 것이 좋습니다. 이렇게 하면 중첩된 라우터를 사용할 때 특정 경로 그룹에만 해당 레이아웃을 적용할 수 있어 유연하게 사용할 수 있습니다.
+1. **App layer에서 인라인으로 layout 작성하기**
+ App layer에서 직접 layout을 정의하는 것이 좋습니다. 이렇게 하면 중첩된 라우터를 사용할 때 특정 경로 그룹에만 해당 layout을 적용할 수 있어 유연하게 사용할 수 있습니다.
2. **복사하여 붙여넣기**
- 코드 추상화는 항상 좋은 선택은 아닙니다. 특히 레이아웃은 자주 변경되지 않기 때문에, 필요한 경우 해당 페이지만 수정하는 것이 더 효율적일 수 있습니다. 이렇게 하면 다른 페이지에 영향을 주지 않고 수정할 수 있습니다. 팀원들이 다른 페이지를 수정하는 걸 잊을까 봐 걱정된다면, 페이지 간의 관계를 주석으로 남겨보세요. 큰 프로젝트에서도 협업이 더 편해질 거예요.
+ 코드 추상화는 항상 좋은 선택은 아닙니다. 특히 layout은 자주 변경되지 않기 때문에, 필요한 경우 해당 page만 수정하는 것이 더 효율적일 수 있습니다. 이렇게 하면 다른 page에 영향을 주지 않고 수정할 수 있습니다. 팀원들이 다른 page를 수정하는 걸 잊을까 봐 걱정된다면, page 간의 관계를 주석으로 남겨보세요. 큰 프로젝트에서도 협업이 더 편해질 거예요.
-위의 내용이 적절하지 않은 경우, 레이아웃에 widget을 포함하는 두 가지 해결책이 있습니다:
+위의 내용이 적절하지 않은 경우, layout에 widget을 포함하는 두 가지 해결책이 있습니다:
1. **render props나 slots 사용하기**
대부분의 프레임워크에서는 컴포넌트 내부에 표시될 UI 요소를 외부에서 전달할 수 있는 기능을 제공합니다. React에서는 [render props][ext-render-props]라고 하며, Vue에서는 [slots][ext-vue-slots]이라고 부릅니다.
-2. **레이아웃을 App 레이어로 이동하기**
- 레이아웃을 `app/layouts` 등 App 레이어에 저장하고 원하는 widget을 구성할 수도 있습니다.
+2. **layout을 App layer로 이동하기**
+ layout을 `app/layouts` 등 App layer에 저장하고 원하는 widget을 구성할 수도 있습니다.
## 추가 자료
-React 및 Remix(React Router와 유사)의 인증 레이아웃 구축에 대한 예시는 [튜토리얼][tutorial]에서 확인하실 수 있습니다.
+React 및 Remix(React Router와 유사)의 인증 layout 구축에 대한 예시는 [튜토리얼][tutorial]에서 확인하실 수 있습니다.
[tutorial]: /docs/get-started/tutorial
diff --git a/i18n/kr/docusaurus-plugin-content-docs/current/guides/examples/types.md b/i18n/kr/docusaurus-plugin-content-docs/current/guides/examples/types.md
index 5b07e9106..12519e26c 100644
--- a/i18n/kr/docusaurus-plugin-content-docs/current/guides/examples/types.md
+++ b/i18n/kr/docusaurus-plugin-content-docs/current/guides/examples/types.md
@@ -40,18 +40,18 @@ type ArrayValues = T[number];
:::warning
-`shared/types` 폴더를 생성하거나 각 슬라이스에 `types`라는 세그먼트를 추가하고 싶은 마음이 들 수 있지만, 그렇게 하지 않는 것이 좋습니다.
-`types`라는 카테고리는 `components`나 `hooks`와 마찬가지로 내용이 무엇인지를 설명할 뿐, 코드의 목적을 명확히 설명하지 않습니다. 슬라이스는 해당 코드의 목적을 정확히 설명할 수 있어야 합니다.
+`shared/types` 폴더를 생성하거나 각 slice에 `types`라는 segment를 추가하고 싶은 마음이 들 수 있지만, 그렇게 하지 않는 것이 좋습니다.
+`types`라는 카테고리는 `components`나 `hooks`와 마찬가지로 내용이 무엇인지를 설명할 뿐, 코드의 목적을 명확히 설명하지 않습니다. slice는 해당 코드의 목적을 정확히 설명할 수 있어야 합니다.
:::
-## 비즈니스 엔티티 및 상호 참조 관계
+## 비즈니스 entity 및 상호 참조 관계
-앱에서 가장 중요한 타입 중 하나는 비즈니스 엔티티, 즉 앱에서 다루는 객체들 입니다.
-예를 들어, 음악 스트리밍 앱에서는 _Song_, _Album_ 등이 비즈니스 엔티티가 될 수 있습니다.
+앱에서 가장 중요한 타입 중 하나는 비즈니스 entity, 즉 앱에서 다루는 객체들 입니다.
+예를 들어, 음악 스트리밍 앱에서는 _Song_, _Album_ 등이 비즈니스 entity가 될 수 있습니다.
-비즈니스 엔티티는 주로 백엔드 바탕이기 떄문에, 백엔드 응답을 타입으로 정의하는 것이 첫 번째 단계입니다.
-각 엔드포인트에 대한 요청 함수와 그 응답을 타입으로 지정하는 것이 좋습니다, 추가적인 타입 안정성을 위해 [Zod][ext-zod]와 같은 스키마 검증 라이브러리를 사용해 응답을 검증할 수도 있습니다.
+비즈니스 entity는 주로 백엔드 바탕이기 떄문에, 백엔드 응답을 타입으로 정의하는 것이 첫 번째 단계입니다.
+각 endpoint에 대한 요청 함수와 그 응답을 타입으로 지정하는 것이 좋습니다, 추가적인 타입 안정성을 위해 [Zod][ext-zod]와 같은 스키마 검증 라이브러리를 사용해 응답을 검증할 수도 있습니다.
예를 들어, 모든 요청을 Shared에 보관하는 경우 이렇게 작성할 수 있습니다.
@@ -69,14 +69,14 @@ export function listSongs() {
}
```
-`Song` 타입은 다른 엔티티인 `Artist`를 참조합니다. 이와 같이 요청 관련 코드들을 Shared에 관리하면, 타입들의 서로 얽혀 있을 떄 관리가 용이해집니다. 만약 이 함수를 `entities/song/api`에 보관했다면, `entities/artist`에서 간단히 가져오는 것이 어려웠을 것 입니다. FSD 구조에서는 [레이어별 import 규칙][import-rule-on-layers]을 통해 슬라이스 간의 교차 import를 제한하고 있기 떄문입니다:
+`Song` 타입은 다른 entity인 `Artist`를 참조합니다. 이와 같이 요청 관련 코드들을 Shared에 관리하면, 타입들의 서로 얽혀 있을 떄 관리가 용이해집니다. 만약 이 함수를 `entities/song/api`에 보관했다면, `entities/artist`에서 간단히 가져오는 것이 어려웠을 것 입니다. FSD 구조에서는 [layer별 import 규칙][import-rule-on-layers]을 통해 slice 간의 교차 import를 제한하고 있기 떄문입니다:
-> 슬라이스 안에 있는 모듈은 계층적으로 더 낮은 레이어에 위치한 슬라이스만 가져올 수 있습니다.
+> slice 안에 있는 module은 계층적으로 더 낮은 layer에 위치한 slice만 가져올 수 있습니다.
이 문제를 해결하기 위한 두 가지 방법은 다음과 같습니다:
1. **타입 매개변수화**
- 타입이 다른 엔티티와 연결될 때, 타입 매개변수를 통해 처리할 수 있습니다. 예를 들어, Song 타입에 ArtistType이라는 제약 조건을 설정할 수 있습니다.
+ 타입이 다른 entity와 연결될 때, 타입 매개변수를 통해 처리할 수 있습니다. 예를 들어, Song 타입에 ArtistType이라는 제약 조건을 설정할 수 있습니다.
```ts title="entities/song/model/song.ts"
interface Song {
@@ -89,7 +89,7 @@ export function listSongs() {
이 방법은 일부 타입에 더 적합합니다. 예를 들어, `Cart = { items: Array }`처럼 간단한 타입은 다양한 제품 타입을 지원하기 쉽게 할 수 있습니다. 하지만 `Country`와 `City`처럼 더 밀접하게 연결된 타입은 분리하기 어렵습니다.
2. **Cross-import (공개 API를 사용해 관리하기)**
- FSD에서 엔티티 간 cross-imports를 허용하기 위해서는 공개 API를 사용할 수 있습니다. 예를 들어, `song`, `artist`, `playlist`라는 엔티티가 있고, 후자의 두 엔티티가 `song`을 참조해야 한다고 가정합니다. 이 경우, `song` 엔티티 내에 `artist`와 `playlist`용 공개 API를 따로 `@x` 표기를 만들어 사용할 수 있습니다.
+ FSD에서 entity 간 cross-imports를 허용하기 위해서는 공개 API를 사용할 수 있습니다. 예를 들어, `song`, `artist`, `playlist`라는 entity가 있고, 후자의 두 entity가 `song`을 참조해야 한다고 가정합니다. 이 경우, `song` entity 내에 `artist`와 `playlist`용 공개 API를 따로 `@x` 표기를 만들어 사용할 수 있습니다.
- 📂 entities
- 📂 song
@@ -115,11 +115,11 @@ export function listSongs() {
}
```
- 이렇게 엔티티 간 명시적으로 연결을 해두면 의존 관계를 파악하고 도메인 분리 수준을 유지하기 쉬워집니다.
+ 이렇게 entity 간 명시적으로 연결을 해두면 의존 관계를 파악하고 도메인 분리 수준을 유지하기 쉬워집니다.
## 데이터 전송 객체와 mappers {#data-transfer-objects-and-mappers}
-데이터 전송 객체(Data Transfer Object, DTO)는 백엔드에서 오는 데이터의 구조를 나타내는 용어입니다. 떄로는 DTO를 그대로 사용하는 것이 편리할 수 있지만, 경우에 따라 프론트엔드에서는 불편할 수 있습니다. 이때 매퍼를 사용해 DTO를 더 편리한 형태로 변환합니다.
+데이터 전송 객체(Data Transfer Object, DTO)는 백엔드에서 오는 데이터의 구조를 나타내는 용어입니다. 떄로는 DTO를 그대로 사용하는 것이 편리할 수 있지만, 경우에 따라 프론트엔드에서는 불편할 수 있습니다. 이때 mapper를 사용해 DTO를 더 편리한 형태로 변환합니다.
### DTO의 위치
@@ -145,7 +145,7 @@ export function listSongs() {
### Mappers의 위치
-Mappers는 DTO를 받아 변환하는 역할을 하므로, DTO 정의와 가까운 위치에 두는 것이 좋습니다. 만약 요청과 DTO가 `shared/api`에 정의되어 있다면, mappers도 그곳에 위치하는 것이 적절합니다.
+Mapper는 DTO를 받아 변환하는 역할을 하므로, DTO 정의와 가까운 위치에 두는 것이 좋습니다. 만약 요청과 DTO가 `shared/api`에 정의되어 있다면, mapper도 그곳에 위치하는 것이 적절합니다.
```ts title="shared/api/songs.ts"
import type { ArtistDTO } from "./artists";
@@ -179,7 +179,7 @@ export function listSongs() {
}
```
-요청과 상태 관리 코드가 엔티티 슬라이스에 정의되어 있는 경우, mappers 역시 해당 슬라이스 내에 두는 것이 좋습니다. 이때 슬라이스 간 교차 참조가 발생하지 않도록 주의해야 합니다.
+요청과 상태 관리 코드가 entity slice에 정의되어 있는 경우, mapper 역시 해당 slice 내에 두는 것이 좋습니다. 이때 slice 간 교차 참조가 발생하지 않도록 주의해야 합니다.
```ts title="entities/song/api/dto.ts"
import type { ArtistDTO } from "entities/artist/@x/song";
@@ -243,7 +243,7 @@ const songsSlice = createSlice({
### 중첩된 DTO 처리 방법
-백엔드 응답에 여러 엔티티가 포함된 경우 문제가 될 수 있습니다. 예를 들어, 곡 정보에 저자의 ID뿐만 아니라 저자 객체 전체가 포함된 경우가 있을 수 있습니다. 이런 상황에서는 엔티티 간의 상호 참조를 피하기 어렵습니다. 데이터를 지우거나 백엔드 팀과 협의하지 않는 한, 이러한 경우에는 슬라이스 간 간접적인 연결 대신 명시적인 교차 참조를 사용하는 것이 좋습니다. 이를 위해 `@x` 표기법을 활용할 수 있으며, 다음은 Redux Toolkit을 사용한 예시입니다:
+백엔드 응답에 여러 entity가 포함된 경우 문제가 될 수 있습니다. 예를 들어, 곡 정보에 저자의 ID뿐만 아니라 저자 객체 전체가 포함된 경우가 있을 수 있습니다. 이런 상황에서는 entity 간의 상호 참조를 피하기 어렵습니다. 데이터를 지우거나 백엔드 팀과 협의하지 않는 한, 이러한 경우에는 slice 간 간접적인 연결 대신 명시적인 교차 참조를 사용하는 것이 좋습니다. 이를 위해 `@x` 표기법을 활용할 수 있으며, 다음은 Redux Toolkit을 사용한 예시입니다:
```ts title="entities/song/model/songs.ts"
import {
@@ -317,7 +317,7 @@ const reducer = slice.reducer
export default reducer
```
-이 방법은 슬라이스 분리의 이점을 다소 제한할 수 있지만, 우리가 제어할 수 없는 두 엔티티 간의 관계를 명확하게 나타냅니다. 만약 이러한 엔티티가 리팩토링되어야 한다면, 함께 리팩토링해야 할 것입니다.
+이 방법은 slice 분리의 이점을 다소 제한할 수 있지만, 우리가 제어할 수 없는 두 entity 간의 관계를 명확하게 나타냅니다. 만약 이러한 entity가 리팩토링되어야 한다면, 함께 리팩토링해야 할 것입니다.
## 전역 타입과 Redux
@@ -325,7 +325,7 @@ export default reducer
1. 애플리케이션 특성이 없는 제너릭 타입
2. 애플리케이션 전체에 알고 있어야 하는 타입
-첫 번째 경우에는 관련 타입을 Shared 폴더 안에 적절한 세그먼트로 배치하면 됩니다. 예를 들어, 분석 전역 변수를 위한 인터페이스가 있다면 `shared/analytics`에 두는 것이 좋습니다.
+첫 번째 경우에는 관련 타입을 Shared 폴더 안에 적절한 segment로 배치하면 됩니다. 예를 들어, 분석 전역 변수를 위한 인터페이스가 있다면 `shared/analytics`에 두는 것이 좋습니다.
:::warning
@@ -333,7 +333,7 @@ export default reducer
:::
-두 번째 경우는 Redux를 사용하지만 RTK가 없는 프로젝트에서 자주 발생합니다. 최종 스토어 타입은 모든 리듀서를 추가한 후에만 사용 가능하지만, 이 스토어 타입은 앱 전체에서 사용하는 셀렉터에 필요합니다. 예를 들어, 일반적인 스토어 정의는 다음과 같습니다:
+두 번째 경우는 Redux를 사용하지만 RTK가 없는 프로젝트에서 자주 발생합니다. 최종 store 타입은 모든 reducer를 추가한 후에만 사용 가능하지만, 이 store 타입은 앱 전체에서 사용하는 selector에 필요합니다. 예를 들어, 일반적인 store 정의는 다음과 같습니다:
```ts title="app/store/index.ts"
import { combineReducers, rootReducer } from "redux";
@@ -349,11 +349,11 @@ type RootState = ReturnType;
type AppDispatch = typeof store.dispatch;
```
-`shared/store`에서 `useAppDispatch`와 `useAppSelector`와 같은 타입이 지정된 Redux 훅을 사용하는 것이 좋지만, [레이어에 대한 import 규칙][import-rule-on-layers] 떄문에 App 레이어에서 `RootState`와 `AppDispatch`를 import 할 수 없습니다.
+`shared/store`에서 `useAppDispatch`와 `useAppSelector`와 같은 타입이 지정된 Redux 훅을 사용하는 것이 좋지만, [layer에 대한 import 규칙][import-rule-on-layers] 때문에 App layer에서 `RootState`와 `AppDispatch`를 import 할 수 없습니다.
-> 슬라이스의 모듈은 더 낮은 레이어에 위치한 다른 슬라이스만 import 할 수 있습니다.
+> slice의 module은 더 낮은 layer에 위치한 다른 slice만 import 할 수 있습니다.
-이 경우 권장되는 해결책은 Shared와 App 레이어 간에 암묵적인 의존성을 만드는 것입니다. `RootState`와 `AppDispatch` 두 타입은 유지보수 필요성이 적고 Redux를 사용하는 개발자들에게 익숙하므로 큰 문제 없이 사용할 수 있습니다.
+이 경우 권장되는 해결책은 Shared와 App layer 간에 암묵적인 의존성을 만드는 것입니다. `RootState`와 `AppDispatch` 두 타입은 유지보수 필요성이 적고 Redux를 사용하는 개발자들에게 익숙하므로 큰 문제 없이 사용할 수 있습니다.
TypeScript에서는 다음과 같이 타입을 전역으로 선언할 수 있습니다:
@@ -375,21 +375,21 @@ export const useAppSelector: TypedUseSelectorHook = useSelector;
**일반적으로 열거형(enum)은 사용되는 위치와 최대한 가까운 곳에 정의하는 것이 좋습니다**. 열거형이 특정 기능과 관련된 값을 나타낸다면, 해당 기능 내에 정의해야 합니다.
-세그먼트 선택도 사용 위치에 따라 달라져야 합니다. 예를 들어, 화면에서 토스트 위치를 나타내는 열거형이라면 ui 세그먼트에 두는 것이 좋고, 백엔드 응답 상태 등을 나타낸다면 api 세그먼트에 두는 것이 적합합니다.
+segment 선택도 사용 위치에 따라 달라져야 합니다. 예를 들어, 화면에서 토스트 위치를 나타내는 열거형이라면 ui segment에 두는 것이 좋고, 백엔드 응답 상태 등을 나타낸다면 api segment에 두는 것이 적합합니다.
-프로젝트 전반에서 공통으로 사용되는 열거형도 있습니다. 예를 들어, 일반적인 백엔드 응답 상태나 디자인 시스템 토큰 등이 있습니다. 이 경우 Shared에 두되, 열거형이 나타내는 것을 기준으로 세그먼트를 선택하면 됩니다 (`api`는 응답 상태, `ui`는 디자인 토큰 등).
+프로젝트 전반에서 공통으로 사용되는 열거형도 있습니다. 예를 들어, 일반적인 백엔드 응답 상태나 디자인 시스템 토큰 등이 있습니다. 이 경우 Shared에 두되, 열거형이 나타내는 것을 기준으로 segment를 선택하면 됩니다 (`api`는 응답 상태, `ui`는 디자인 토큰 등).
## 타입 검증 스키마와 Zod
데이터가 특정 형태나 제약 조건을 충족하는지 검증하려면 검증 스키마를 정의할 수 있습니다. TypeScript에서는 [Zod][ext-zod]와 같은 라이브러리를 많이 사용합니다. 검증 스키마는 가능하면 사용하는 코드와 같은 위치에 두는 것이 좋습니다.
-검증 스키마는 데이터를 파싱하며, 파싱에 실패하면 오류를 발생시킵니다.([Data transfoer objects and mappers](#data-transfer-objects-and-mappers) 토론을 참조하세요.) 가장 일반적인 검증 사례 중 하나는 백엔드에서 오는 데이터에 대한 것입니다. 데이터가 스키마와 일치하지 않는 경우 요청을 실패시키기를 원하기 때문에, 보통 `api` 세그먼트에 스키마를 두는 것이 좋습니다.
+검증 스키마는 데이터를 파싱하며, 파싱에 실패하면 오류를 발생시킵니다.([Data transfoer objects and mappers](#data-transfer-objects-and-mappers) 토론을 참조하세요.) 가장 일반적인 검증 사례 중 하나는 백엔드에서 오는 데이터에 대한 것입니다. 데이터가 스키마와 일치하지 않는 경우 요청을 실패시키기를 원하기 때문에, 보통 `api` segment에 스키마를 두는 것이 좋습니다.
-사용자 입력(예: 폼)으로 데이터를 받을 경우, 입력된 데이터에 대해 바로 검증이 이루어져야 합니다. 이 경우 스키마를 `ui` 세그먼트 내 폼 컴포넌트 옆에 두거나, `ui` 세그먼트가 너무 복잡하다면 `model` 세그먼트에 둘 수 있습니다.
+사용자 입력(예: 폼)으로 데이터를 받을 경우, 입력된 데이터에 대해 바로 검증이 이루어져야 합니다. 이 경우 스키마를 `ui` segment 내 폼 컴포넌트 옆에 두거나, `ui` segment가 너무 복잡하다면 `model` segment에 둘 수 있습니다.
## 컴포넌트 props와 context의 타입 정의
-보통 props나 context 인터페이스는 이를 사용하는 컴포넌트나 컨텍스트와 같은 파일에 두는 것이 가장 좋습니다. 만약 Vue나 Svelte처럼 단일 파일 컴포넌트를 사용하는 프레임워크에서 여러 컴포넌트 간에 해당 인터페이스를 공유해야 한다면, `ui` 세그먼트 내 동일 폴더에 별도의 파일을 만들어 정의할 수 있습니다.
+보통 props나 context 인터페이스는 이를 사용하는 컴포넌트나 컨텍스트와 같은 파일에 두는 것이 가장 좋습니다. 만약 Vue나 Svelte처럼 단일 파일 컴포넌트를 사용하는 프레임워크에서 여러 컴포넌트 간에 해당 인터페이스를 공유해야 한다면, `ui` segment 내 동일 폴더에 별도의 파일을 만들어 정의할 수 있습니다.
예를 들어, React의 JSX에서는 다음과 같이 정의합니다:
@@ -423,7 +423,7 @@ export interface RecentActionsProps {
[Vite][ext-vite]나 [ts-reset][ext-ts-reset] 같은 일부 패키지는 앱 전반에서 작동하기 위해 Ambient 선언 파일을 필요로 합니다. 이러한 파일들은 보통 크거나 복잡하지 않기 때문에 `src/` 폴더에 두어도 괜찮습니다. 더 정리된 구조를 위해 `app/ambient/` 폴더에 두는 것도 좋은 방법입니다.
-타이핑이 없는 패키지인 경우, 해당 패키지를 미타입으로 선언하거나 직접 타이핑을 작성할 수 있습니다. 이러한 타이핑을 위한 좋은 위치는 `shared/lib` 폴더 내의 `shared/lib/untyped-packages` 폴더입니다. 이 폴더에 `%LIBRARY_NAME%.d.ts` 파일을 생성하고 필요한 타입을 선언합니다
+타이핑이 없는 패키지인 경우, 해당 패키지를 미타입으로 선언하거나 직접 타이핑을 작성할 수 있습니다. 이러한 타이핑을 위한 좋은 위치는 `shared/lib` 폴더 내의 `shared/lib/untyped-packages` 폴더입니다. 이 폴더에 `%LIBRARY_NAME%.d.ts` 파일을 생성하고 필요한 타입을 선언합니다
```ts title="shared/lib/untyped-packages/use-react-screenshot.d.ts"
// 이 라이브러리는 타입 정의가 없으며 작성하는 것을 생략했습니다.