# 로케일 및 로컬라이제이션

> Several locales in one site, with a primary locale, machine translation that costs no credits, locale-aware delivery and SEO, and the same contract for hosted and headless front ends.

> Markdown version of https://kanorio.com/ko/developers/products/localization. Append `.md` to any developer docs URL for this format. Index: https://kanorio.com/llms.txt · MCP: https://app.kanorio.com/api/mcp
>
> Translated from the English original: https://kanorio.com/en/developers/products/localization.md

Status: **Available**

사이트에는 하나의 기본 로케일이 있으며 추가 로케일을 설정할 수 있습니다. 모든 텍스트 필드는 기본 로케일 값을 그대로 유지하며, 번역은 레코드와 로케일당 한 행씩 별도의 테이블에 저장됩니다. 로케일을 추가하면 사이트 전체가 백그라운드에서 번역되며 완료 시 게시됩니다. 호스팅된 사이트와 구축한 프론트엔드는 동일한 `locale` 매개변수를 통해 동일한 데이터를 읽습니다.

## 핵심 객체

- **로케일 세트** 사이트의 로케일들입니다. 기본 로케일, 상태(`draft`, `translating`, `published`, `disabled`), 각 보조 로케일의 URL 접두사(`en`, `ko` 또는 소유자가 선택한 접두사), 자동 번역 스위치가 포함됩니다. `GET /api/v1/site`를 호출하면 `locales[]`에 나열됩니다.
- **번역** 레코드와 로케일당 한 행으로 구성되며, 초안 및 게시된 필드 데이터, 고유한 URL 슬러그(한 세그먼트), 번역 당시 원본 레코드의 `sourceHash`를 포함합니다. 이 해시는 오래된 번역을 감지하고 외부 도구가 더 새로운 원본 텍스트를 덮어쓰지 않도록 방지하는 역할을 합니다.
- **번역 가능한 필드** 각 콘텐츠 타입의 스키마에서 파생된 레지스트리로, 번역 가능한 경로를 정의합니다: 제목, 리치 텍스트, 섹션 텍스트, SEO 필드, 제품 설명, 상세 정보, FAQ 및 구매 메모, 제품 옵션 및 변형 설명, 텍스트 레슨과 퀴즈 질문을 포함한 코스 유닛(정답 키 제외), 스토어 전체 처리 시간 및 구매 메모, 폼 및 법적 페이지. 컬렉션 필드는 `localized: true`로 설정하여 활성화합니다. 가격, 재고, 주문, 고객 및 리뷰는 번역되지 않습니다.
- **URL 슬러그** 각 로케일은 페이지, 게시물, 카테고리, 태그, 작성자, 제품, 제품 카테고리 및 컬렉션 아이템에 대해 고유한 슬러그를 가질 수 있습니다. 로케일로의 첫 번째 기계 번역 시 번역된 제목에서 생성됩니다(라틴 문자 언어는 ASCII 슬러그를 사용하며, 다른 스크립트는 ASCII인 경우 기본 슬러그를 유지). 이후에는 자동으로 변경되지 않습니다. 페이지는 자신의 세그먼트만 번역하므로, 로케일 내 페이지 경로는 해당 로케일의 각 레벨 슬러그를 조합하여 생성됩니다. `/blog`나 `/product`와 같은 고정 퍼머링크 세그먼트는 번역되지 않습니다.
- **번역 작업** 로케일이 추가되거나 누락된 배치가 재시도될 때 사이트 전체 작업이 실행됩니다. 이후 기본 로케일에 대한 수정 사항은 점진적으로 재번역됩니다. 작업 및 단일 레코드 번역은 AI 크레딧을 소모하지 않으며, 일일 호출 한도에 도달하면 실패하는 대신 다음 날로 작업이 대기열에 추가됩니다.

## 설정 간의 관계

로케일, 통화, 비즈니스 시장, 시간대는 4개의 독립적인 설정입니다. 서로 파생되지 않으므로 영어로 작성하고 유로로 판매하며 도쿄 시간으로 운영되는 사이트를 만들 수 있습니다. 고객의 로케일(`Contact.locale`)은 결제, 로그인, 폼 제출 시 기록되며 이메일, 고객 계정 및 인증서의 로케일을 결정합니다.

## API 활용 방법

- **Content Delivery API를 통한 읽기** 모든 읽기 요청은 `locale`(코드 또는 URL 접두사)을 허용합니다. 번역되지 않은 필드는 기본 텍스트로 대체되며, 응답에는 `resolvedLocale`(제공된 로케일)과 `availableLocales`(번역이 존재하는 로케일)가 포함됩니다. 슬러그를 통한 읽기는 모든 로케일의 슬러그를 허용하며 요청된 로케일의 `slug`를 반환합니다. 페이지와 제품에는 `localePaths`(모든 활성 로케일에서의 경로)가 추가되고 컬렉션 아이템에는 `localeSlugs`가 추가됩니다. 사이트에 없는 로케일을 요청하면 `400 UNSUPPORTED_LOCALE`이 반환됩니다. `/seo/*`, `/feed` 및 검색도 동일한 매개변수를 따릅니다. [콘텐츠 읽기](https://kanorio.com/ko/developers/guides/read-content)를 참조하세요.
- **Management API를 통한 관리** `localization.locales.*`를 통해 로케일을 추가, 업데이트, 재정렬, 제거하고 기본 로케일을 설정합니다. `localization.translations.*`를 통해 번역을 나열, 읽기, 쓰기(`sourceHash`를 사용한 `upsert` 및 로케일의 URL 슬러그를 설정하거나 지우기 위한 `slug`), 게시, 삭제하며 `translate`를 통해 요청 시 번역을 실행합니다. `localization.jobs.*`를 통해 진행 상황을 읽고 재시도합니다. 로케일 추가 또는 제거는 모든 URL을 변경하므로 `confirm: true`가 필요합니다. 로케일 코드는 자연 키입니다. 세트에 이미 있는 로케일을 추가하면 `ALREADY_ADDED`가 반환되고, 없는 로케일을 제거하면 `NOT_FOUND`가 반환되므로 재시도 호출이 로케일을 중복 생성하지 않으며 멱등성 키가 필요하지 않습니다.
- **Webhook 수신** `content.translation.published` 및 `deleted`는 레코드와 로케일당 발생합니다. `localization.locale.published`, `unpublished` 및 `updated`는 로케일 세트가 변경될 때 발생합니다. `localization.job.completed` 및 `failed`는 사이트 전체 작업에 대해 발생합니다. 모든 콘텐츠 이벤트의 `cacheTags`에는 `@<locale>`이 포함되어 있어 번역이 게시되면 해당 로케일만 새로고침됩니다. [Webhooks](https://kanorio.com/ko/developers/webhooks)를 참조하세요.
- **프론트엔드 라우팅 및 태그 지정** `createKanorioMiddleware({ features: { locales: true } })`는 기본 로케일 접두사를 루트로 리다이렉트하고, `/<prefix>/llms.txt` 및 `/<prefix>/rss.xml`을 제공하며, 접두사 없는 공유 리다이렉트와 전체 경로에 대한 로케일 리다이렉트(`locale` 세트)를 매칭합니다. `requestLocaleOf`, `buildAlternates`, `languageSwitcher`(`localePaths` 전달)를 사용하면 호스팅된 사이트와 동일한 규칙으로 로케일, 캐노니컬, hreflang 및 언어 메뉴를 얻을 수 있습니다. [Next.js](https://kanorio.com/ko/developers/guides/nextjs) 및 [SDK 참조](https://kanorio.com/ko/developers/sdk)를 참조하세요.
- **고객 대상 텍스트** Customer API 및 `@kanorio/elements`는 `locale`을 허용하며, 지정하지 않으면 고객의 기록된 로케일을 사용합니다. 코스 및 유닛 제목, 주문 라인 이름, 수료증은 이를 따릅니다. [코스 및 멤버](https://kanorio.com/ko/developers/guides/courses-and-members)를 참조하세요.
- **자동 이메일** 주문, 결제, 배송, 환불, 로그인 및 폼 확인 이메일은 사이트가 제공하는 경우 고객의 기록된 로케일로, 그렇지 않으면 기본 로케일로 발송됩니다. 소유자가 사용자 정의하지 않은 이메일은 모든 사이트 언어에 대해 존재하는 내장 문구를 사용합니다. 사용자 정의 이메일은 다른 콘텐츠처럼 번역됩니다. 해당 번역은 `message_template` 레코드 타입(사용자 정의 템플릿 ID)이며 `localization.translations.*`를 통해 로케일별로 수정되고 쓰기 시 반영됩니다. 로케일에 사용자 정의 이메일 번역이 있을 때까지 해당 이메일은 기본 로케일로 발송됩니다. 템플릿 변수(주문 번호와 같은 삼중 중괄호 자리 표시자)는 원본과 정확히 일치해야 하며, 변수를 추가하는 번역은 거부됩니다.
- **내보내기** 사이트 내보내기에는 기본 로케일 콘텐츠와 함께 `localization/locales.json` 및 `localization/translations.json`이 포함됩니다.

## 신뢰할 수 있는 동작

- 기본 로케일은 루트에서 제공되며, 다른 모든 로케일은 해당 접두사 아래에서 제공됩니다. 기본 로케일의 코드를 접두사로 사용하면 `301` 리다이렉트를 통해 루트로 이동합니다.
- 번역 중인 로케일은 방문자나 Delivery API에 존재하지 않는 것으로 간주됩니다. 작업이 완료되면 로케일이 한 번에 게시됩니다.
- 활성화되었던 로케일을 제거하면 해당 접두사는 기본 로케일 페이지로 리다이렉트됩니다. 번역은 최소 30일간 유지되며, 로케일을 다시 추가하면 재사용되고 누락된 부분만 번역됩니다. 이전 URL을 복구하려면 동일한 접두사를 지정하세요.
- 폴백으로 제공되는 페이지(아직 로케일 번역이 없는 경우)는 기본 로케일의 캐노니컬을 가져오며 hreflang이 없으므로 검색 엔진이 중복 텍스트를 인덱싱하지 않습니다.
- 초안 및 게시 수명 주기가 있는 레코드(페이지, 전역 섹션, 사이트 설정, 게시물 및 컬렉션 아이템)는 수정된 번역을 초안으로 유지합니다. 레코드를 게시하면 모든 로케일의 초안이 게시됩니다. `localization.translations.publish`는 특정 로케일만 게시하며 레코드의 게시 권한(`site:publish`, `blog:publish` 또는 `collections:publish`)이 필요합니다. 번역을 수정해도 기본 로케일이 변경된 것으로 표시되지 않습니다.
- 다른 로케일의 슬러그를 사용하는 URL이나 로케일 고유 슬러그가 있는 경우의 기본 슬러그는 해당 로케일의 슬러그로 리다이렉트됩니다. 활성 슬러그를 변경하면 해당 로케일의 이전 URL에서 `301` 리다이렉트가 추가되며, 지우면 로케일이 다시 기본 슬러그를 따르게 됩니다.
- 사이트에 로케일이 하나만 있는 경우 기본 로케일을 변경할 수 있습니다. 다국어 사이트에서의 변경은 모든 URL을 다시 작성해야 하므로 아직 제공되지 않습니다.
- 동일한 규칙이 호스팅된 사이트와 헤드리스 프론트엔드에 적용됩니다. `npx @kanorio/cli doctor`는 프론트엔드가 각 로케일을 번역된 제목과 함께 접두사 아래에서 제공하는지, 모든 활성 로케일에 대해 hreflang을 나열하는지, 로케일별 `llms.txt`를 제공하는지 확인합니다.

## What the APIs expose

| Capability | Status | API | Elements | Hosted site | Webhooks |
| --- | --- | --- | --- | --- | --- |
| Locale set & translations (add a locale, full-site machine translation, review) | Available | Management API `localization.locales.*` (`list`, `add`, `update`, `reorder`, `remove`, `set_primary`), `localization.translations.*` (`list`, `get`, `upsert` with `sourceHash`, `publish`, `delete`, `translate`), `localization.jobs.*`; REST `/sites/:id/locales`, `/sites/:id/translations` | — | `/settings` locale list (status, progress, URL prefix, auto-translate) and the editor's locale switcher for corrections | `content.translation.published` / `deleted`, `localization.locale.published` / `unpublished` / `updated`, `localization.job.completed` / `failed` |
| Locale-aware delivery, SEO files and customer-facing text | Available | Delivery `?locale=` (code or URL prefix) on `/site`, `/pages`, `/globals`, `/collections`, `/catalog`, `/forms`, `/search`, `/seo/*` and `/feed` with `resolvedLocale` / `availableLocales` / `localePaths` (collection items: `localeSlugs`), any locale's slug resolves to the record; `/redirects` rules carry `locale`; Customer API `locale` on deliverables, orders and unit open; SDK `createKanorioMiddleware({ features: { locales } })`, `buildAlternates`, `requestLocaleOf`, `languageSwitcher`, locale-scoped `revalidate`; CLI `doctor` i18n rules | `locale` on `<KanorioProvider>` (forms, login, curriculum and unit load the visitor's locale) | Primary locale at the root, other locales under their prefix (`/en/…`), header language menu, per-locale `llms.txt` / `rss.xml`, one sitemap with `xhtml:link`, hreflang and `x-default` | `cacheTags` on every content event carry `@<locale>` so a translation going live refreshes only that locale |

## API reference

- Management API: [Localization](https://kanorio.com/en/developers/management-api/localization) (16 operations)

## Webhook events

- `content.translation.published`: Fired when one record's translation in one locale goes live on its own (editor correction, Management API write, incremental or on-demand machine translation). cacheTags carry only that locale's tags. Not fired per record during a full-site translation job; see localization.job.completed.
- `content.translation.deleted`: Fired when a live translation of one record in one locale is deleted; visitors see the primary-locale text until it is translated again.
- `localization.locale.published`: Fired when a locale goes live for visitors and the Content Delivery API (a full-site translation job finished, or the owner published it). cacheTags is site:<id>: rebuild the language switcher and hreflang on every page.
- `localization.locale.unpublished`: Fired when a live locale is taken offline or removed (removed: true); its URL prefix now 301-redirects to the primary locale.
- `localization.locale.updated`: Fired when a live locale's URL prefix (change: path_prefix, previous holds the old prefix), its position in the language switcher (order) or the site's primary locale (primary) changes.
- `localization.job.completed`: Fired when a full-site translation job finishes. cacheTags is locale:<code>: every response of that locale may have changed. A locale going live for the first time also fires localization.locale.published.
- `localization.job.failed`: Fired when a full-site translation job fails (the model provider stayed unavailable or retries ran out; the daily limit only pauses a job). Retry it with localization.jobs.retry.

Payloads: https://kanorio.com/en/developers/webhooks/events

## Recent changes

- 2026-11-04: Localization: automated emails follow the customer's language
- 2026-11-04: Localization: publishing one locale needs the record's publish permission
- 2026-11-04: Localization: more translatable fields (product details, variants, lessons, quizzes, store notes)
- 2026-11-04: Localization: each locale can have its own URL slug
- 2026-11-03: Localization is generally available; site export includes locales and translations

Full changelog: https://kanorio.com/en/developers/changelog

## For site owners

Dashboard help: https://kanorio.com/ko/help/multilingual-site
