This is an automated email from the ASF dual-hosted git repository.
morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris-website.git
The following commit(s) were added to refs/heads/master by this push:
new 9afaea163cc [feat](i18n) Add optional Korean documentation preview
(#4353)
9afaea163cc is described below
commit 9afaea163cc22fd523b0a9761b5e6db920bd3d2b
Author: Mingyu Chen (Rayner) <[email protected]>
AuthorDate: Sun Oct 18 14:31:54 2026 +0100
[feat](i18n) Add optional Korean documentation preview (#4353)
## Summary
Adds an opt-in Korean documentation preview. `DORIS_ENABLE_KO=true`
enables Korean alone; `DORIS_ENABLE_LOCALES=ja,ko` enables both managed
languages. Korean stays disabled in the existing production deployment
configuration.
- Adds Korean source policy, Hangul validation, search context labels,
scope, glossary and independent page state.
- Translates four native pages: the Dev overview, the Dev
getting-started MDX page, the 4.x overview and the community entry page.
Other documents use the existing same-version English fallback. All four
records retain machine review status and need human Korean proofreading.
- Adds essential status, source-link, search, version and navigation
messages. Korean ordinary pages remain undeclared; Japanese translated
pages remain registered.
- Removes Japanese-only assumptions from both link gates and related
tests, so links to untranslated Korean neighbors resolve to their actual
source plugin and version.
## Validation
- Node 20: 176 tests passed, zero failures; one existing Apache
integration test skipped by its environment guard.
- Python link resolution: six tests passed, including Korean Dev, 4.x
and community fallback.
- All four samples passed strict protected-content, English heading IDs,
MDX syntax, glossary, Hangul and internal-link checks. Source and target
hashes were calculated from the actual files at Apache master
`c1dc0ada58258822db4f31d9f05b11cf3e011b7b`.
- Four-language Dev build passed in separate processes on the clean PR
head, with local assets and search enabled. Korean and Japanese static
verification each covered 1,810 pages with no skipped counterparts;
Korean has three current pages in this Dev-only artifact.
- Chromium passed MDX card navigation, English fallback, body language,
canonical/noindex, query/hash, back/refresh, and all eight themes at
1440/390 widths. No page errors or failed local resources. Korean server
analyzer and browser worker smoke passed; complete browser search
acceptance remains T04.
- Admission checks passed for both managed locales; Korean checked all
four samples across native plugin/version identities with zero errors or
warnings. GitHub Build Check is pending.
The Korean inventory, browser search acceptance, production enablement
and translation workflow are subsequent tasks.
Co-authored-by: morningman <[email protected]>
---
config/i18n.js | 3 +-
i18n/ko/code.json | 152 ++++++++++++++++++++
.../current.json | 11 ++
.../current/join-community.md | 75 ++++++++++
.../ko/docusaurus-plugin-content-docs/current.json | 8 ++
.../current/getting-started/intro.mdx | 95 +++++++++++++
.../getting-started/what-is-apache-doris.md | 155 +++++++++++++++++++++
.../version-4.x.json | 8 ++
.../getting-started/what-is-apache-doris.md | 155 +++++++++++++++++++++
i18n/ko/docusaurus-theme-classic/footer.json | 8 ++
scripts/__tests__/test_japanese_links.py | 21 +++
scripts/check_md_links_single.py | 4 +-
scripts/check_move.js | 9 +-
scripts/i18n/__tests__/locale-registry.test.cjs | 35 ++++-
scripts/i18n/__tests__/state.test.cjs | 4 +-
scripts/i18n/__tests__/t04.test.cjs | 18 +--
translations/config.json | 11 ++
translations/glossary/ko.json | 69 +++++++++
translations/scope/ko.json | 27 ++++
translations/state/ko/docs.json | 4 +
.../ko/pages/community/current/join-community.json | 20 +++
.../4.x/getting-started/what-is-apache-doris.json | 20 +++
.../default/current/getting-started/intro.json | 20 +++
.../getting-started/what-is-apache-doris.json | 20 +++
translations/state/ko/resolved-deletions.json | 4 +
translations/state/ko/shards.schema.json | 4 +
26 files changed, 935 insertions(+), 25 deletions(-)
diff --git a/config/i18n.js b/config/i18n.js
index 4402450135b..1adbcb1a28a 100644
--- a/config/i18n.js
+++ b/config/i18n.js
@@ -25,9 +25,10 @@ const localeRegistry = [
'/use-cases/observability',
'/use-cases/ai',
]},
+ {code: 'ko', label: '한국어', htmlLang: 'ko', optional: true, ordinaryPages:
false},
];
const locales = localeRegistry.map(locale => locale.code);
-// ja reads DORIS_ENABLE_JA, a future ko reads DORIS_ENABLE_KO. CI enables
+// ja reads DORIS_ENABLE_JA, ko reads DORIS_ENABLE_KO. CI enables
// exactly the locales one change can reach through DORIS_ENABLE_LOCALES, so it
// never has to name a language in the workflow.
const flagFor = locale =>
`DORIS_ENABLE_${locale.code.split('-')[0].toUpperCase()}`;
diff --git a/i18n/ko/code.json b/i18n/ko/code.json
new file mode 100644
index 00000000000..4db0fd95933
--- /dev/null
+++ b/i18n/ko/code.json
@@ -0,0 +1,152 @@
+{
+ "docs.translation.status.label": {
+ "message": "번역 상태"
+ },
+ "docs.translation.untranslated": {
+ "message": "이 페이지는 아직 한국어로 번역되지 않았습니다."
+ },
+ "docs.translation.showingSource": {
+ "message": "현재 버전의 영어 원문을 표시합니다."
+ },
+ "docs.translation.openSource": {
+ "message": "영어 원문 보기"
+ },
+ "docs.translation.openChineseSource": {
+ "message": "중국어 원문 보기"
+ },
+ "docs.translation.staleProse": {
+ "message": "한국어 번역에 원문의 최신 표현이 반영되지 않았습니다."
+ },
+ "docs.translation.sourceMissing": {
+ "message": "원문을 확인할 수 없어 한국어 번역을 표시하지 않습니다."
+ },
+ "docs.translation.unverified": {
+ "message": "한국어 번역의 내용이나 최신 상태를 확인하지 못했습니다."
+ },
+ "docs.translation.stale": {
+ "message": "한국어 번역에 원문의 최신 변경 사항이 반영되지 않았습니다."
+ },
+ "docs.translation.reviewedHuman": {
+ "message": "사람이 교정한 한국어 번역입니다."
+ },
+ "docs.translation.machine": {
+ "message": "이 페이지는 기계 번역되었습니다."
+ },
+ "docs.translation.translatedAt": {
+ "message": "번역일: "
+ },
+ "theme.docs.versions.unreleasedVersionLabel": {
+ "message": "이 문서는 Apache Doris의 {unreleased} 버전을 위한 문서입니다."
+ },
+ "theme.docs.versions.unreleasedText": {
+ "message": "개발 중인"
+ },
+ "theme.docs.versions.latestVersionSuggestionLabel": {
+ "message": "사용 방법은 버전 {v4xLink} / {v3xLink} / {v21Link}의 공식 문서를 참고하세요."
+ },
+ "theme.docs.versions.unmaintainedVersionLabel": {
+ "message": "현재 유지 관리되지 않는 {siteTitle} {versionLabel}의 문서입니다."
+ },
+ "theme.docs.versions.latestVersionLinkLabel": {
+ "message": "최신 버전"
+ },
+ "theme.navbar.mobileVersionsDropdown.label": {
+ "message": "다른 버전"
+ },
+ "theme.navbar.mobileLanguageDropdown.label": {
+ "message": "다른 언어"
+ },
+ "theme.SearchBar.noResultsText": {
+ "message": "검색 결과가 없습니다"
+ },
+ "theme.SearchBar.seeAllOutsideContext": {
+ "message": "\"{context}\" 외의 모든 결과 보기"
+ },
+ "theme.SearchBar.searchInContext": {
+ "message": "\"{context}\" 내의 모든 결과 보기"
+ },
+ "theme.SearchBar.seeAll": {
+ "message": "모든 결과 보기"
+ },
+ "theme.SearchBar.label": {
+ "message": "검색"
+ },
+ "theme.SearchPage.existingResultsTitle": {
+ "message": "\"{query}\" 검색 결과"
+ },
+ "theme.SearchPage.emptyResultsTitle": {
+ "message": "문서 검색"
+ },
+ "theme.SearchPage.searchContext.everywhere": {
+ "message": "전체"
+ },
+ "theme.SearchPage.documentsFound.plurals": {
+ "message": "문서 {count}개를 찾았습니다"
+ },
+ "theme.SearchPage.noResultsText": {
+ "message": "문서를 찾지 못했습니다"
+ },
+ "theme.SearchPage.searchSource": {
+ "message": "영어 원문 검색"
+ },
+ "theme.docs.paginator.navAriaLabel": {
+ "message": "문서 페이지"
+ },
+ "theme.docs.paginator.previous": {
+ "message": "이전"
+ },
+ "theme.docs.paginator.next": {
+ "message": "다음"
+ },
+ "theme.docs.breadcrumbs.home": {
+ "message": "홈"
+ },
+ "theme.docs.breadcrumbs.navAriaLabel": {
+ "message": "현재 문서 경로"
+ },
+ "theme.docs.sidebar.navAriaLabel": {
+ "message": "문서 탐색"
+ },
+ "theme.docs.sidebar.closeSidebarButtonAriaLabel": {
+ "message": "탐색 메뉴 닫기"
+ },
+ "theme.docs.sidebar.toggleSidebarButtonAriaLabel": {
+ "message": "탐색 메뉴 열기/닫기"
+ },
+ "theme.docs.sidebar.collapseButtonTitle": {
+ "message": "탐색 메뉴 접기"
+ },
+ "theme.docs.sidebar.collapseButtonAriaLabel": {
+ "message": "탐색 메뉴 접기"
+ },
+ "theme.docs.sidebar.expandButtonTitle": {
+ "message": "탐색 메뉴 펼치기"
+ },
+ "theme.docs.sidebar.expandButtonAriaLabel": {
+ "message": "탐색 메뉴 펼치기"
+ },
+ "theme.docs.versionBadge.label": {
+ "message": "버전: {versionLabel}"
+ },
+ "theme.common.editThisPage": {
+ "message": "이 페이지 편집"
+ },
+ "theme.common.headingLinkTitle": {
+ "message": "{heading} 직접 링크"
+ },
+ "theme.common.skipToMainContent": {
+ "message": "본문으로 건너뛰기"
+ },
+ "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": {
+ "message": "← 주 메뉴로 돌아가기"
+ },
+ "theme.TOCCollapsible.toggleButtonLabel": {
+ "message": "이 페이지의 내용"
+ },
+ "theme.TOC.title": {
+ "message": "이 페이지의 내용"
+ },
+ "theme.NavBar.navAriaLabel": {
+ "message": "주 메뉴"
+ }
+}
diff --git a/i18n/ko/docusaurus-plugin-content-docs-community/current.json
b/i18n/ko/docusaurus-plugin-content-docs-community/current.json
new file mode 100644
index 00000000000..c6137ab8356
--- /dev/null
+++ b/i18n/ko/docusaurus-plugin-content-docs-community/current.json
@@ -0,0 +1,11 @@
+{
+ "version.label": {
+ "message": "커뮤니티"
+ },
+ "sidebar.community.category.About the Community": {
+ "message": "커뮤니티 소개"
+ },
+ "sidebar.community.category.How to Contribute": {
+ "message": "기여 방법"
+ }
+}
diff --git
a/i18n/ko/docusaurus-plugin-content-docs-community/current/join-community.md
b/i18n/ko/docusaurus-plugin-content-docs-community/current/join-community.md
new file mode 100644
index 00000000000..3ba7274cc45
--- /dev/null
+++ b/i18n/ko/docusaurus-plugin-content-docs-community/current/join-community.md
@@ -0,0 +1,75 @@
+---
+title: 커뮤니티 참여
+language: ko
+description: "Apache Doris 커뮤니티 참여 방법: Slack, GitHub, 메일링 리스트, Twitter,
LinkedIn, YouTube, Bilibili의 공식 채널과 링크를 안내합니다."
+keywords:
+ - Apache Doris 커뮤니티
+ - Doris 커뮤니티 참여
+ - Doris Slack
+ - Doris GitHub
+ - Doris 메일링 리스트
+ - Doris 오픈 소스 커뮤니티
+ - Apache 최상위 프로젝트
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Apache Doris 커뮤니티 참여 {#join-the-apache-doris-community}
+
+<!-- Knowledge type: Procedure -->
+<!-- Applicable scenario: New user onboarding / Joining the community -->
+
+[Apache Doris](https://github.com/apache/doris)는 전 세계 사용자와 개발자가 함께 유지 관리하는 오픈
소스 실시간 데이터 웨어하우스 프로젝트입니다. 2022년 유월 Apache Incubator를 졸업하여 Apache 최상위 프로젝트
(TLP)가 되었습니다. 이 페이지에서는 커뮤니티의 공식 소통 채널을 안내합니다. 자신에게 맞는 채널을 선택하여 토론에 참여하고 소식을
받아보세요.
+
+:::tip 커뮤니티에 기여하고 싶으신가요?
+
+코드 개발, 콘텐츠 제작, 커뮤니티 홍보를 통해 Apache Doris에 기여하고 싶다면 [커뮤니티 기여
가이드](how-to-contribute/contribute-to-doris.mdx)부터 확인하세요.
+
+:::
+
+## 공식 커뮤니티 채널 개요 {#overview-of-official-community-channels}
+
+각 채널의 목적과 활용 방법은 다음과 같습니다.
+
+| 채널 | 목적 | 참여 링크 |
+|------|------|------|
+| Slack | 실시간 토론과 질의응답 (신규 사용자에게 권장) |
[https://doris.apache.org/slack](https://doris.apache.org/slack?utm_source=website&utm_medium=docs&utm_content=community_join_page)
|
+| GitHub | 소스 코드, 이슈, PR, 릴리스 노트 | <https://github.com/apache/doris> |
+| 메일링 리스트 | Apache의 공식 비동기 토론 및 의사 결정 채널 | [메일링 리스트 구독](subscribe-mail-list)
참고 |
+| Twitter | 전 세계 사용자 사례, 릴리스 소식, 행사 안내 | <https://twitter.com/doris_apache> |
+| LinkedIn | 기술 인맥 확장, 채용 및 업계 소식 |
<https://www.linkedin.com/company/doris-apache/> |
+| YouTube | 해외 Meetup 및 기술 발표 녹화 영상 |
<https://www.youtube.com/hashtag/apachedoris> |
+| Bilibili | 중국 내 Meetup 및 기술 발표 녹화 영상 |
<https://space.bilibili.com/362350065> |
+
+## 상황에 맞는 채널 선택 {#choose-a-channel-by-scenario}
+
+<!-- Knowledge type: Scenario routing -->
+
+- **간단한 질문이나 일상적인 토론에 참여하려면**:
[Slack](https://doris.apache.org/slack?utm_source=website&utm_medium=docs&utm_content=community_join_page)에
참여하세요.
+- **버그를 보고하거나 코드를 제출하려면**: [GitHub](https://github.com/apache/doris)를 방문하고
[피드백](feedback)과 [커뮤니티 기여 가이드](how-to-contribute/contribute-to-doris.mdx)를
참고하세요.
+- **커뮤니티 의사 결정과 릴리스 공지를 확인하려면**: [메일링 리스트를 구독](subscribe-mail-list)하세요.
+- **사용자 사례와 기술 인사이트를 보려면**: [Twitter](https://twitter.com/doris_apache)와
[LinkedIn](https://www.linkedin.com/company/doris-apache/)을 팔로우하세요.
+- **Meetup 및 기술 발표 녹화 영상을 보려면**:
[YouTube](https://www.youtube.com/hashtag/apachedoris) 또는
[Bilibili](https://space.bilibili.com/362350065)를 방문하세요.
+
+## 다음 단계 {#next-steps}
+
+- [메일링 리스트 구독](subscribe-mail-list): 5단계로 dev 메일링 리스트 구독을 완료합니다.
+- [피드백](feedback): 버그나 제안을 제출하는 공식 절차입니다.
+- [보안 취약점 공개](security): ASF 보안 팀에 취약점을 보고합니다.
diff --git a/i18n/ko/docusaurus-plugin-content-docs/current.json
b/i18n/ko/docusaurus-plugin-content-docs/current.json
new file mode 100644
index 00000000000..5fa04682685
--- /dev/null
+++ b/i18n/ko/docusaurus-plugin-content-docs/current.json
@@ -0,0 +1,8 @@
+{
+ "version.label": {
+ "message": "Dev"
+ },
+ "sidebar.docs.category.Getting Started": {
+ "message": "시작하기"
+ }
+}
diff --git
a/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/intro.mdx
b/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/intro.mdx
new file mode 100644
index 00000000000..7286c40cdc1
--- /dev/null
+++ b/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/intro.mdx
@@ -0,0 +1,95 @@
+---
+{
+ "title": "Apache Doris 시작하기",
+ "language": "ko",
+ "description": "Apache Doris 시작 가이드: 빠른 시작, 설치, 배포 등"
+}
+---
+
+import GettingStartedCard from
'@site/src/components/getting-started-card/getting-started-card';
+
+# Apache Doris 시작하기 {#apache-doris-getting-started}
+
+Apache Doris에 오신 것을 환영합니다! 이 가이드는 필요에 맞는 자료를 찾는 데 도움을 드립니다.
+
+## Apache Doris를 처음 사용합니다 {#i-am-new-to-apache-doris}
+
+<div className="cards-grid">
+<GettingStartedCard
+ title="Apache Doris 소개"
+ description="Apache Doris의 아키텍처, 핵심 기능, 기술적 특징을 알아보세요"
+ link="what-is-apache-doris"
+/>
+
+<GettingStartedCard
+ title="빠른 시작"
+ description="몇 분 만에 Apache Doris를 실행해 보세요"
+ link="quick-start"
+/>
+
+<GettingStartedCard
+ title="POC 준비 가이드"
+ description="POC 전에 필요한 하드웨어 준비와 환경 설정 권장 사항을 확인하세요"
+ link="before-you-start-the-poc"
+/>
+</div>
+
+## 다른 기술에서 마이그레이션하려고 합니다 {#i-am-migrating-from-another-technology}
+
+<div className="cards-grid">
+<GettingStartedCard
+ title="ClickHouse 대안"
+ description="Apache Doris가 ClickHouse와 어떻게 다르며 어떻게 대체할 수 있는지 알아보세요"
+ link="/why-doris/compare#clickhouse"
+/>
+
+<GettingStartedCard
+ title="Elasticsearch 대안"
+ description="Apache Doris를 Elasticsearch의 대안으로 활용하는 방법을 알아보세요"
+ link="/why-doris/compare#elastic"
+/>
+
+<GettingStartedCard
+ title="Trino 대안"
+ description="Apache Doris로 Trino를 대체하거나 함께 사용하는 방법을 알아보세요"
+ link="/why-doris/compare#trino"
+/>
+</div>
+
+## Apache Doris를 배포하려고 합니다 {#i-want-to-deploy-apache-doris}
+
+<div className="cards-grid">
+<GettingStartedCard
+ title="설치 및 배포"
+ description="환경에 맞는 배포 방법을 선택하세요"
+ link="../install/intro"
+/>
+
+<GettingStartedCard
+ title="Kubernetes 배포"
+ description="Doris Operator로 Kubernetes에 배포하세요"
+ link="../install/deploy-on-kubernetes/intro"
+/>
+</div>
+
+## 더 알아보고 싶습니다 {#i-want-to-explore-further}
+
+<div className="cards-grid">
+<GettingStartedCard
+ title="사용 사례"
+ description="실제 활용 사례와 성공 사례를 살펴보세요"
+ link="/why-doris/users"
+/>
+
+<GettingStartedCard
+ title="벤치마크"
+ description="성능 벤치마크 결과를 확인하세요"
+ link="/why-doris/benchmarks"
+/>
+
+<GettingStartedCard
+ title="아키텍처와 개념"
+ description="Doris의 내부 동작을 자세히 알아보세요"
+ link="../features-architecture/intro"
+/>
+</div>
diff --git
a/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/what-is-apache-doris.md
b/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/what-is-apache-doris.md
new file mode 100644
index 00000000000..82ede0a5a57
--- /dev/null
+++
b/i18n/ko/docusaurus-plugin-content-docs/current/getting-started/what-is-apache-doris.md
@@ -0,0 +1,155 @@
+---
+{
+ 'title': 'Apache Doris 개요',
+ 'language': 'ko',
+ 'sidebar_label': 'Apache Doris 소개',
+ 'description': "Apache Doris는 MPP 아키텍처 기반의 고성능 실시간 분석 데이터베이스입니다. 효율성, 단순성,
통합성을 바탕으로 대규모 데이터 세트에 대한 쿼리 결과를 1초 미만에 반환합니다. 동시성이 높은 포인트 쿼리와 처리량이 높은 복잡한 분석을
모두 지원합니다."
+}
+---
+
+<div class="doris-doc-intro-animation" align="center">
+ <iframe
+ class="doris-doc-intro-animation__frame"
+ src="/animations/what-is-apache-doris-intro.html?embed=1&v=3"
+ title="Apache Doris 소개 애니메이션"
+ width="960"
+ height="540"
+ loading="lazy"
+ ></iframe>
+</div>
+
+<p>
+Apache Doris는 MPP 아키텍처 기반의 고성능 실시간 분석 데이터베이스입니다. <strong>효율성, 단순성,
통합성</strong>을 바탕으로 대규모 데이터 세트에 대한 쿼리 결과를 일 초 미만에 반환하며, 하나의 시스템에서 동시성이 높은 포인트
쿼리와 처리량이 높은 복잡한 분석을 모두 지원합니다.
+</p>
+
+<div align="center">
+
+
+
+</div>
+
+## 주요 특징 {#core-highlights}
+
+| 기능 | 수치 및 사양 |
+|------|------|
+| 쿼리 지연 시간 | **< 1초** (서브초 응답) |
+| 데이터 수집 지연 시간 | **초 단위** (실시간 데이터 수집) |
+| 동시 처리 성능 | **10,000+ QPS** |
+| 저장 규모 | **PB급** / 클러스터당 수백 대의 머신 |
+| SQL 인터페이스 | **MySQL 프로토콜 호환 계층**, ANSI SQL 문법 |
+
+## 주요 사용 사례 {#typical-use-cases}
+
+Apache Doris는 다음 세 가지 유형의 시나리오에서 널리 사용됩니다.
+
+### 실시간 데이터 분석 {#real-time-data-analytics}
+
+내부 및 외부 실시간 보고서, 대시보드, 사용자 행동 분석, A/B 테스트 플랫폼, 로그 검색 및 분석에 사용합니다.
+
+**대표 사례**:
+- 실시간 대시보드: 초 단위로 갱신되는 광군제 주문량 모니터링
+- 사용자 프로필 분석: 고객 세분화 및 정밀 마케팅
+- 로그 검색 및 분석: 문제 해결 및 성능 최적화
+
+### 레이크하우스 분석 {#lakehouse-analytics}
+
+통합 데이터 웨어하우스 구축, 데이터 레이크에 대한 연합 쿼리 가속, 혼합 워크로드 분석에 사용합니다.
+
+<div align="center">
+
+
+
+</div>
+
+### 하이브리드 검색 및 분석 (AI 데이터 스택) {#hybrid-search-and-analytics-ai-data-stack}
+
+대규모 모델 시대에 Apache Doris는 **전문 검색, 벡터 검색, AI 함수** 기능을 긴밀하게 통합하여 데이터 저장, 검색, 분석을
아우르는 완전한 AI 데이터 스택을 구축합니다.
+
+| 시나리오 | 설명 |
+|------|------|
+| **에이전트용 분석** | AI 에이전트를 위한 밀리초 단위 실시간 의사 결정 (사기 탐지, 지능형 추천) |
+| **하이브리드 검색 및 분석** | 하나의 SQL 문에서 벡터 유사도 검색, 키워드 필터링, 집계 분석을 함께 실행 |
+| **RAG 애플리케이션** | 기업 지식 기반 질의응답, 지능형 고객 서비스, 문서 어시스턴트 |
+| **의미 검색** | 언어 간 검색, 동의어 인식, 의도 파악 |
+| **AI 관측 가능성** | 모델 학습 모니터링, 추론 추적, 로그 분석 |
+
+## 시스템 아키텍처 {#system-architecture}
+
+Apache Doris는 MySQL 프로토콜과 높은 호환성을 갖추고 표준 SQL을 지원합니다. 다양한 클라이언트 도구로 접근할 수 있으며
BI 도구와도 원활하게 연동됩니다. 배포 시 비즈니스 요구 사항에 따라 **스토리지와 컴퓨팅 통합 아키텍처** 또는 **스토리지와 컴퓨팅 분리
아키텍처**를 선택할 수 있습니다.
+
+<div align="center">
+
+
+
+</div>
+
+### 스토리지와 컴퓨팅 통합 아키텍처 {#integrated-storage-and-compute-architecture}
+
+두 가지 유형의 프로세스로 구성된 간결한 아키텍처입니다.
+
+- **Frontend (FE)**: 요청 수신, 쿼리 구문 분석, 메타데이터 관리, 노드 관리를 담당합니다.
+- **Backend (BE)**: 데이터를 저장하고 쿼리를 실행합니다 (다중 복제본 저장).
+
+운영 환경에서는 고가용성을 위해 여러 FE 노드를 배포합니다. FE 노드에는 Master, Follower, Observer의 세 가지
역할이 있습니다.
+
+### 스토리지와 컴퓨팅 분리 아키텍처 (공유 스토리지)
{#decoupled-storage-and-compute-architecture-shared-storage}
+
+스토리지와 컴퓨팅을 분리하여 **저장 용량과 컴퓨팅 리소스를 독립적으로 확장**할 수 있습니다.
+
+- **컴퓨팅 계층**: 여러 컴퓨팅 그룹으로 구성되며, 각 그룹은 독립적인 테넌트를 지원할 수 있습니다.
+- **스토리지 계층**: S3, HDFS, OSS 등의 공유 스토리지를 사용합니다.
+
+**선택 기준**: 비즈니스 규모가 감당할 만하고 간단한 운영을 선호한다면 통합 아키텍처를 선택합니다. 탄력적인 확장이 필요하다면 분리
아키텍처를 선택합니다.
+
+## 기술적 특징 {#technical-features}
+
+### 스토리지 엔진 {#storage-engine}
+
+Apache Doris는 컬럼형 저장 기술을 사용하여 데이터를 컬럼 단위로 인코딩, 압축, 읽기 처리합니다. 이를 통해 높은 압축률을
달성하고 불필요한 데이터 스캔을 줄여 IO와 CPU 리소스를 효율적으로 사용합니다. 초광폭 테이블 시나리오 (10,000+ 컬럼)에 맞춰
최적화되어 희소 컬럼을 효율적으로 저장하고 쿼리할 수 있습니다. 다양한 비즈니스 시나리오를 지원하기 위해 여러 인덱스 구조 (Sorted
Compound Key, Min/Max, BloomFilter, 역색인, 벡터 인덱스)와 저장 모델 (Duplicate 모델,
Aggregate 모델, Unique 모델)을 제공합니다. 또한 강한 일관성을 보장하는 단일 테이블 구체화된 뷰와 비동기로 갱신되는 다중
테이블 구체화된 뷰를 지원합니다.
+
+- **컬럼형 저장**: 컬럼 단위 인코딩, 압축, 읽기로 높은 압축률을 달성하고 IO를 줄입니다.
+- **다양한 인덱스**: Sorted Compound Key, Min/Max, BloomFilter, **역색인**, **벡터 인덱스**
+- **저장 모델**: Duplicate 모델, Aggregate 모델, Unique 모델 (행 단위 업데이트 지원)
+- **구체화된 뷰**: 강한 일관성을 보장하는 단일 테이블 구체화된 뷰와 비동기 다중 테이블 구체화된 뷰
+
+> **벡터 인덱스와 역색인은 Hybrid Search (하이브리드 검색 및 분석)를 지원하는 핵심 기술입니다**. 자세한 내용은 [AI
개요](../ai/ai-overview.md)를 참고하세요.
+
+### 쿼리 엔진 {#query-engine}
+
+Apache Doris 쿼리 엔진은 MPP (Massively Parallel Processing) 아키텍처를 기반으로 노드 간 및 노드 내
병렬 실행과 여러 대용량 테이블 간 분산 Shuffle Join을 지원합니다. 복잡한 다중 테이블 조인 시나리오에서는 전역 쿼리 계획, 분산
조인 전략, Runtime Filter 기술을 사용하여 데이터 전송을 크게 줄이고 조인 성능을 높입니다. Doris는 벡터화 실행을
사용합니다. 모든 메모리 내 구조가 컬럼형 레이아웃을 사용하므로 가상 함수 호출을 크게 줄이고 캐시 적중률을 높이며 SIMD 명령어를
효율적으로 활용합니다. 이를 통해 와이드 테이블 집계 시나리오에서 5-10배의 성능 향상을 제공합니다. Adaptive Query
Execution (AQE)과 Pipeline 실행 엔진을 결합하여 런타임 통계를 기반으로 실행 계획을 동적으로 최적화하고 멀티코어 CPU를
충분히 활용합니다.
+
+- **MPP 아키텍처**: 노드 간 및 노드 내 병렬 실행, 대용량 테이블을 위한 분산 Shuffle Join
+- **벡터화 실행**: 컬럼형 메모리 레이아웃, SIMD 명령어, 5-10배 성능 향상
+- **Adaptive Query Execution (AQE)**: Runtime Filter로 조인을 동적으로 최적화합니다.
+- **Pipeline 실행 엔진**: 멀티코어 CPU에서 병렬로 실행하며, 스레드 수 제한으로 스레드 과다 생성을 방지합니다.
+
+### 하이브리드 검색 기능 (AI 강화) {#hybrid-search-capabilities-ai-enhanced}
+
+Apache Doris는 하나의 SQL 문에 **정형 데이터 분석, 전문 검색, 벡터 검색**을 결합합니다. 데이터 이동이나 이기종 시스템
통합 없이 하나의 시스템에서 벡터 유사도 검색, 키워드 필터링, 집계 분석을 함께 지원합니다. 동적 JSON 구조를 기본 지원하는
VARIANT 타입과 초 단위 필드 변경을 지원하는 Light Schema Change를 결합하여 RAG 애플리케이션, 의미 검색, 기업 지식
기반 등의 AI 시나리오에 효율적인 데이터 기반을 제공합니다.
+
+```sql
+SELECT * FROM products
+WHERE match(query_vector, 'summer breathable shoes') -- Vector similarity
search
+ AND body MATCH 'breathable lightweight' -- Full-text keyword search
+ AND category_id = 1 -- Structured filtering
+GROUP BY brand
+ORDER BY sales_count DESC;
+```
+
+- **통합 아키텍처**: 데이터 이동이나 이기종 시스템 통합이 필요하지 않습니다.
+- **하이브리드 쿼리 성능**: 하나의 SQL 문에서 벡터, 키워드, 집계 연산을 함께 실행합니다.
+- **VARIANT 타입**: 동적 JSON을 기본 지원하며, Light Schema Change로 초 단위 필드 변경이 가능합니다.
+
+## 생태계 연동 {#ecosystem-integration}
+
+Apache Doris는 주요 데이터 생태계와 긴밀하게 연동됩니다.
+
+<div align="center">
+
+
+
+</div>
+
+## 커뮤니티 및 기여 {#community-and-contribution}
+
+커뮤니티에 참여해 주세요: https://doris.apache.org/community/join-community
diff --git a/i18n/ko/docusaurus-plugin-content-docs/version-4.x.json
b/i18n/ko/docusaurus-plugin-content-docs/version-4.x.json
new file mode 100644
index 00000000000..95233672e17
--- /dev/null
+++ b/i18n/ko/docusaurus-plugin-content-docs/version-4.x.json
@@ -0,0 +1,8 @@
+{
+ "version.label": {
+ "message": "4.x"
+ },
+ "sidebar.docs.category.Getting Started": {
+ "message": "시작하기"
+ }
+}
diff --git
a/i18n/ko/docusaurus-plugin-content-docs/version-4.x/getting-started/what-is-apache-doris.md
b/i18n/ko/docusaurus-plugin-content-docs/version-4.x/getting-started/what-is-apache-doris.md
new file mode 100644
index 00000000000..82ede0a5a57
--- /dev/null
+++
b/i18n/ko/docusaurus-plugin-content-docs/version-4.x/getting-started/what-is-apache-doris.md
@@ -0,0 +1,155 @@
+---
+{
+ 'title': 'Apache Doris 개요',
+ 'language': 'ko',
+ 'sidebar_label': 'Apache Doris 소개',
+ 'description': "Apache Doris는 MPP 아키텍처 기반의 고성능 실시간 분석 데이터베이스입니다. 효율성, 단순성,
통합성을 바탕으로 대규모 데이터 세트에 대한 쿼리 결과를 1초 미만에 반환합니다. 동시성이 높은 포인트 쿼리와 처리량이 높은 복잡한 분석을
모두 지원합니다."
+}
+---
+
+<div class="doris-doc-intro-animation" align="center">
+ <iframe
+ class="doris-doc-intro-animation__frame"
+ src="/animations/what-is-apache-doris-intro.html?embed=1&v=3"
+ title="Apache Doris 소개 애니메이션"
+ width="960"
+ height="540"
+ loading="lazy"
+ ></iframe>
+</div>
+
+<p>
+Apache Doris는 MPP 아키텍처 기반의 고성능 실시간 분석 데이터베이스입니다. <strong>효율성, 단순성,
통합성</strong>을 바탕으로 대규모 데이터 세트에 대한 쿼리 결과를 일 초 미만에 반환하며, 하나의 시스템에서 동시성이 높은 포인트
쿼리와 처리량이 높은 복잡한 분석을 모두 지원합니다.
+</p>
+
+<div align="center">
+
+
+
+</div>
+
+## 주요 특징 {#core-highlights}
+
+| 기능 | 수치 및 사양 |
+|------|------|
+| 쿼리 지연 시간 | **< 1초** (서브초 응답) |
+| 데이터 수집 지연 시간 | **초 단위** (실시간 데이터 수집) |
+| 동시 처리 성능 | **10,000+ QPS** |
+| 저장 규모 | **PB급** / 클러스터당 수백 대의 머신 |
+| SQL 인터페이스 | **MySQL 프로토콜 호환 계층**, ANSI SQL 문법 |
+
+## 주요 사용 사례 {#typical-use-cases}
+
+Apache Doris는 다음 세 가지 유형의 시나리오에서 널리 사용됩니다.
+
+### 실시간 데이터 분석 {#real-time-data-analytics}
+
+내부 및 외부 실시간 보고서, 대시보드, 사용자 행동 분석, A/B 테스트 플랫폼, 로그 검색 및 분석에 사용합니다.
+
+**대표 사례**:
+- 실시간 대시보드: 초 단위로 갱신되는 광군제 주문량 모니터링
+- 사용자 프로필 분석: 고객 세분화 및 정밀 마케팅
+- 로그 검색 및 분석: 문제 해결 및 성능 최적화
+
+### 레이크하우스 분석 {#lakehouse-analytics}
+
+통합 데이터 웨어하우스 구축, 데이터 레이크에 대한 연합 쿼리 가속, 혼합 워크로드 분석에 사용합니다.
+
+<div align="center">
+
+
+
+</div>
+
+### 하이브리드 검색 및 분석 (AI 데이터 스택) {#hybrid-search-and-analytics-ai-data-stack}
+
+대규모 모델 시대에 Apache Doris는 **전문 검색, 벡터 검색, AI 함수** 기능을 긴밀하게 통합하여 데이터 저장, 검색, 분석을
아우르는 완전한 AI 데이터 스택을 구축합니다.
+
+| 시나리오 | 설명 |
+|------|------|
+| **에이전트용 분석** | AI 에이전트를 위한 밀리초 단위 실시간 의사 결정 (사기 탐지, 지능형 추천) |
+| **하이브리드 검색 및 분석** | 하나의 SQL 문에서 벡터 유사도 검색, 키워드 필터링, 집계 분석을 함께 실행 |
+| **RAG 애플리케이션** | 기업 지식 기반 질의응답, 지능형 고객 서비스, 문서 어시스턴트 |
+| **의미 검색** | 언어 간 검색, 동의어 인식, 의도 파악 |
+| **AI 관측 가능성** | 모델 학습 모니터링, 추론 추적, 로그 분석 |
+
+## 시스템 아키텍처 {#system-architecture}
+
+Apache Doris는 MySQL 프로토콜과 높은 호환성을 갖추고 표준 SQL을 지원합니다. 다양한 클라이언트 도구로 접근할 수 있으며
BI 도구와도 원활하게 연동됩니다. 배포 시 비즈니스 요구 사항에 따라 **스토리지와 컴퓨팅 통합 아키텍처** 또는 **스토리지와 컴퓨팅 분리
아키텍처**를 선택할 수 있습니다.
+
+<div align="center">
+
+
+
+</div>
+
+### 스토리지와 컴퓨팅 통합 아키텍처 {#integrated-storage-and-compute-architecture}
+
+두 가지 유형의 프로세스로 구성된 간결한 아키텍처입니다.
+
+- **Frontend (FE)**: 요청 수신, 쿼리 구문 분석, 메타데이터 관리, 노드 관리를 담당합니다.
+- **Backend (BE)**: 데이터를 저장하고 쿼리를 실행합니다 (다중 복제본 저장).
+
+운영 환경에서는 고가용성을 위해 여러 FE 노드를 배포합니다. FE 노드에는 Master, Follower, Observer의 세 가지
역할이 있습니다.
+
+### 스토리지와 컴퓨팅 분리 아키텍처 (공유 스토리지)
{#decoupled-storage-and-compute-architecture-shared-storage}
+
+스토리지와 컴퓨팅을 분리하여 **저장 용량과 컴퓨팅 리소스를 독립적으로 확장**할 수 있습니다.
+
+- **컴퓨팅 계층**: 여러 컴퓨팅 그룹으로 구성되며, 각 그룹은 독립적인 테넌트를 지원할 수 있습니다.
+- **스토리지 계층**: S3, HDFS, OSS 등의 공유 스토리지를 사용합니다.
+
+**선택 기준**: 비즈니스 규모가 감당할 만하고 간단한 운영을 선호한다면 통합 아키텍처를 선택합니다. 탄력적인 확장이 필요하다면 분리
아키텍처를 선택합니다.
+
+## 기술적 특징 {#technical-features}
+
+### 스토리지 엔진 {#storage-engine}
+
+Apache Doris는 컬럼형 저장 기술을 사용하여 데이터를 컬럼 단위로 인코딩, 압축, 읽기 처리합니다. 이를 통해 높은 압축률을
달성하고 불필요한 데이터 스캔을 줄여 IO와 CPU 리소스를 효율적으로 사용합니다. 초광폭 테이블 시나리오 (10,000+ 컬럼)에 맞춰
최적화되어 희소 컬럼을 효율적으로 저장하고 쿼리할 수 있습니다. 다양한 비즈니스 시나리오를 지원하기 위해 여러 인덱스 구조 (Sorted
Compound Key, Min/Max, BloomFilter, 역색인, 벡터 인덱스)와 저장 모델 (Duplicate 모델,
Aggregate 모델, Unique 모델)을 제공합니다. 또한 강한 일관성을 보장하는 단일 테이블 구체화된 뷰와 비동기로 갱신되는 다중
테이블 구체화된 뷰를 지원합니다.
+
+- **컬럼형 저장**: 컬럼 단위 인코딩, 압축, 읽기로 높은 압축률을 달성하고 IO를 줄입니다.
+- **다양한 인덱스**: Sorted Compound Key, Min/Max, BloomFilter, **역색인**, **벡터 인덱스**
+- **저장 모델**: Duplicate 모델, Aggregate 모델, Unique 모델 (행 단위 업데이트 지원)
+- **구체화된 뷰**: 강한 일관성을 보장하는 단일 테이블 구체화된 뷰와 비동기 다중 테이블 구체화된 뷰
+
+> **벡터 인덱스와 역색인은 Hybrid Search (하이브리드 검색 및 분석)를 지원하는 핵심 기술입니다**. 자세한 내용은 [AI
개요](../ai/ai-overview.md)를 참고하세요.
+
+### 쿼리 엔진 {#query-engine}
+
+Apache Doris 쿼리 엔진은 MPP (Massively Parallel Processing) 아키텍처를 기반으로 노드 간 및 노드 내
병렬 실행과 여러 대용량 테이블 간 분산 Shuffle Join을 지원합니다. 복잡한 다중 테이블 조인 시나리오에서는 전역 쿼리 계획, 분산
조인 전략, Runtime Filter 기술을 사용하여 데이터 전송을 크게 줄이고 조인 성능을 높입니다. Doris는 벡터화 실행을
사용합니다. 모든 메모리 내 구조가 컬럼형 레이아웃을 사용하므로 가상 함수 호출을 크게 줄이고 캐시 적중률을 높이며 SIMD 명령어를
효율적으로 활용합니다. 이를 통해 와이드 테이블 집계 시나리오에서 5-10배의 성능 향상을 제공합니다. Adaptive Query
Execution (AQE)과 Pipeline 실행 엔진을 결합하여 런타임 통계를 기반으로 실행 계획을 동적으로 최적화하고 멀티코어 CPU를
충분히 활용합니다.
+
+- **MPP 아키텍처**: 노드 간 및 노드 내 병렬 실행, 대용량 테이블을 위한 분산 Shuffle Join
+- **벡터화 실행**: 컬럼형 메모리 레이아웃, SIMD 명령어, 5-10배 성능 향상
+- **Adaptive Query Execution (AQE)**: Runtime Filter로 조인을 동적으로 최적화합니다.
+- **Pipeline 실행 엔진**: 멀티코어 CPU에서 병렬로 실행하며, 스레드 수 제한으로 스레드 과다 생성을 방지합니다.
+
+### 하이브리드 검색 기능 (AI 강화) {#hybrid-search-capabilities-ai-enhanced}
+
+Apache Doris는 하나의 SQL 문에 **정형 데이터 분석, 전문 검색, 벡터 검색**을 결합합니다. 데이터 이동이나 이기종 시스템
통합 없이 하나의 시스템에서 벡터 유사도 검색, 키워드 필터링, 집계 분석을 함께 지원합니다. 동적 JSON 구조를 기본 지원하는
VARIANT 타입과 초 단위 필드 변경을 지원하는 Light Schema Change를 결합하여 RAG 애플리케이션, 의미 검색, 기업 지식
기반 등의 AI 시나리오에 효율적인 데이터 기반을 제공합니다.
+
+```sql
+SELECT * FROM products
+WHERE match(query_vector, 'summer breathable shoes') -- Vector similarity
search
+ AND body MATCH 'breathable lightweight' -- Full-text keyword search
+ AND category_id = 1 -- Structured filtering
+GROUP BY brand
+ORDER BY sales_count DESC;
+```
+
+- **통합 아키텍처**: 데이터 이동이나 이기종 시스템 통합이 필요하지 않습니다.
+- **하이브리드 쿼리 성능**: 하나의 SQL 문에서 벡터, 키워드, 집계 연산을 함께 실행합니다.
+- **VARIANT 타입**: 동적 JSON을 기본 지원하며, Light Schema Change로 초 단위 필드 변경이 가능합니다.
+
+## 생태계 연동 {#ecosystem-integration}
+
+Apache Doris는 주요 데이터 생태계와 긴밀하게 연동됩니다.
+
+<div align="center">
+
+
+
+</div>
+
+## 커뮤니티 및 기여 {#community-and-contribution}
+
+커뮤니티에 참여해 주세요: https://doris.apache.org/community/join-community
diff --git a/i18n/ko/docusaurus-theme-classic/footer.json
b/i18n/ko/docusaurus-theme-classic/footer.json
new file mode 100644
index 00000000000..0b5395127c7
--- /dev/null
+++ b/i18n/ko/docusaurus-theme-classic/footer.json
@@ -0,0 +1,8 @@
+{
+ "link.title.Resources": {
+ "message": "자료"
+ },
+ "link.title.Community": {
+ "message": "커뮤니티"
+ }
+}
diff --git a/scripts/__tests__/test_japanese_links.py
b/scripts/__tests__/test_japanese_links.py
index a005f39e3c6..954a2a13d9c 100644
--- a/scripts/__tests__/test_japanese_links.py
+++ b/scripts/__tests__/test_japanese_links.py
@@ -15,6 +15,8 @@ class JapaneseLinkResolution(unittest.TestCase):
'/docs/4.x/reference/topic':
'versioned_docs/version-4.x/reference/topic.md',
'/ja/docs/dev/reference/topic':
'i18n/ja/docusaurus-plugin-content-docs/current/reference/topic.md',
'/ja/docs/4.x/reference/topic':
'i18n/ja/docusaurus-plugin-content-docs/version-4.x/reference/topic.mdx',
+ '/ko/docs/dev/reference/topic':
'i18n/ko/docusaurus-plugin-content-docs/current/reference/topic.md',
+ '/ko/docs/4.x/reference/topic':
'i18n/ko/docusaurus-plugin-content-docs/version-4.x/reference/topic.mdx',
'/zh-CN/docs/dev/reference/topic':
'i18n/zh-CN/docusaurus-plugin-content-docs/current/reference/topic.mdx',
'/zh-CN/docs/4.x/reference/topic':
'i18n/zh-CN/docusaurus-plugin-content-docs/version-4.x/reference/topic.md',
}
@@ -107,5 +109,24 @@ class JapaneseLinkResolution(unittest.TestCase):
self.assertEqual(resolve_internal(str(localized),
'/ja/community/guide/next'), str(source))
+ def test_korean_fallback_uses_same_plugin_and_version(self):
+ with tempfile.TemporaryDirectory() as temp:
+ root = Path(temp)
+ (root / 'static').mkdir()
+ for plugin, version, source_root in (
+ ('docusaurus-plugin-content-docs', 'current', 'docs'),
+ ('docusaurus-plugin-content-docs', 'version-4.x',
'versioned_docs/version-4.x'),
+ ('docusaurus-plugin-content-docs-community', 'current',
'community'),
+ ):
+ with self.subTest(plugin=plugin, version=version):
+ base = root / f'i18n/ko/{plugin}/{version}/guide'
+ base.mkdir(parents=True)
+ source = root / source_root / 'reference/topic.mdx'
+ source.parent.mkdir(parents=True)
+ source.write_text('# English fallback\n')
+ self.assertEqual(resolve_internal(str(base),
'../reference/topic.mdx'), str(source))
+ self.assertIsNone(resolve_internal(str(base),
'../reference/missing.mdx'))
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/scripts/check_md_links_single.py b/scripts/check_md_links_single.py
index b63b9bc0fa0..ce7d54dad89 100755
--- a/scripts/check_md_links_single.py
+++ b/scripts/check_md_links_single.py
@@ -143,7 +143,7 @@ def resolve_internal(base_dir: str, target: str):
# another redirect alone is not sufficient.
path_part = _doc_redirects(site_root).get(path_part.rstrip("/"),
path_part)
rel = path_part.lstrip("/")
- routed =
re.match(r"(?:(ja|zh-CN)/)?(docs/(dev|[^/]+)|community|releases|course)/(.*)",
rel)
+ routed =
re.match(r"(?:([a-z]{2}(?:-[A-Za-z0-9]+)*)/)?(docs/(dev|[^/]+)|community|releases|course)/(.*)",
rel)
if routed:
locale, route, version, rest = routed.groups()
if route.startswith("docs/"):
@@ -182,7 +182,7 @@ def resolve_internal(base_dir: str, target: str):
site_root, _ = _find_site_roots(base_dir)
if site_root:
relative = os.path.relpath(full, site_root).replace(os.sep, "/")
- localized =
re.match(r"i18n/ja/docusaurus-plugin-content-docs(-[^/]+)?/(current|version-([^/]+))/(.*)",
relative)
+ localized =
re.match(r"i18n/[^/]+/docusaurus-plugin-content-docs(-[^/]+)?/(current|version-([^/]+))/(.*)",
relative)
if localized:
suffix, _, version, rest = localized.groups()
roots = {None: "docs", "-community": "community", "-releases":
"releasenotes", "-course": "course"}
diff --git a/scripts/check_move.js b/scripts/check_move.js
index 5e5b2f59987..011de09d081 100644
--- a/scripts/check_move.js
+++ b/scripts/check_move.js
@@ -8,6 +8,8 @@ const { execSync } = require("child_process");
const fs = require("fs");
const path = require("path");
const { sourceForLocalized } = require("./i18n/paths.cjs");
+const { managedLocales } = require("./i18n/state.cjs");
+const translationLocales = new Set(managedLocales(path.resolve(__dirname,
"..")));
const commitHash = process.argv[2];
@@ -55,10 +57,9 @@ function isLocalLink(link) {
function existingLocalTarget(filePath, rawLink) {
const candidates = [path.resolve(path.dirname(filePath), rawLink)];
- // The Japanese docs plugin intentionally serves the English page when a
- // translation is absent. Resolve its relative links from the same plugin
- // and version of the English source; keep the EN/ZH gate unchanged.
- if (filePath.startsWith("i18n/ja/")) {
+ // Managed docs locales serve English when a translation is absent. Resolve
+ // relative links from that same plugin/version; keep the EN/ZH gate
unchanged.
+ if (filePath.startsWith("i18n/") &&
translationLocales.has(filePath.split("/")[1])) {
const source = sourceForLocalized(filePath);
if (source) candidates.push(path.resolve(path.dirname(source), rawLink));
}
diff --git a/scripts/i18n/__tests__/locale-registry.test.cjs
b/scripts/i18n/__tests__/locale-registry.test.cjs
index 219a4d2211f..33c8ea46ace 100644
--- a/scripts/i18n/__tests__/locale-registry.test.cjs
+++ b/scripts/i18n/__tests__/locale-registry.test.cjs
@@ -28,27 +28,32 @@ function withEnv(values, run) {
test('the locale registry keeps introduced locales opt-in behind one config',
() => {
const {locales, localeRegistry, enabledLocales, enabledLocaleRecords} =
load();
- assert.deepEqual(locales, ['en', 'zh-CN', 'ja']);
+ assert.deepEqual(locales, ['en', 'zh-CN', 'ja', 'ko']);
+ assert.deepEqual(localeRegistry.find(locale => locale.code === 'ko'),
+ {code: 'ko', label: '한국어', htmlLang: 'ko', optional: true,
ordinaryPages: false});
assert.equal(localeRegistry.find(locale => locale.code === 'ja').label,
'日本語');
assert.equal(localeRegistry.find(locale => locale.code === 'ja').htmlLang,
'ja');
- withEnv({DORIS_ENABLE_JA: undefined, DORIS_ENABLE_LOCALES: undefined}, ()
=> {
+ withEnv({DORIS_ENABLE_KO: undefined, DORIS_ENABLE_JA: undefined,
DORIS_ENABLE_LOCALES: undefined}, () => {
assert.deepEqual(enabledLocales(), ['en', 'zh-CN']);
});
// A developer switches one locale on; CI enables the locales in scope.
- withEnv({DORIS_ENABLE_JA: 'true', DORIS_ENABLE_LOCALES: undefined}, () => {
+ withEnv({DORIS_ENABLE_KO: undefined, DORIS_ENABLE_JA: 'true',
DORIS_ENABLE_LOCALES: undefined}, () => {
assert.deepEqual(enabledLocales(), ['en', 'zh-CN', 'ja']);
});
- withEnv({DORIS_ENABLE_JA: undefined, DORIS_ENABLE_LOCALES: 'ja'}, () => {
+ withEnv({DORIS_ENABLE_KO: undefined, DORIS_ENABLE_JA: undefined,
DORIS_ENABLE_LOCALES: 'ja'}, () => {
assert.deepEqual(enabledLocales(), ['en', 'zh-CN', 'ja']);
assert.deepEqual(enabledLocaleRecords().map(locale =>
locale.htmlLang), ['en-US', 'zh-Hans-CN', 'ja']);
});
- withEnv({DORIS_ENABLE_JA: undefined, DORIS_ENABLE_LOCALES: 'ko'}, () => {
- assert.deepEqual(enabledLocales(), ['en', 'zh-CN']);
+ withEnv({DORIS_ENABLE_KO: 'true', DORIS_ENABLE_JA: undefined,
DORIS_ENABLE_LOCALES: undefined}, () => {
+ assert.deepEqual(enabledLocales(), ['en', 'zh-CN', 'ko']);
+ });
+ withEnv({DORIS_ENABLE_KO: undefined, DORIS_ENABLE_JA: undefined,
DORIS_ENABLE_LOCALES: 'ja,ko'}, () => {
+ assert.deepEqual(enabledLocales(), ['en', 'zh-CN', 'ja', 'ko']);
});
});
test('a locale is managed only when it is both configured and enabled', () => {
- assert.deepEqual(managedLocales(root), ['ja']);
+ assert.deepEqual(managedLocales(root), ['ja', 'ko']);
assert.deepEqual(managedLocales(root, ['en', 'zh-CN', 'ja']), ['ja']);
assert.deepEqual(managedLocales(root, ['en', 'zh-CN']), []);
});
@@ -107,4 +112,20 @@ test('neither shipped locale translates the blog yet', ()
=> {
const {hasBlogTranslations} = load();
assert.equal(hasBlogTranslations(root, 'zh-CN'), false);
assert.equal(hasBlogTranslations(root, 'ja'), false);
+ assert.equal(hasBlogTranslations(root, 'ko'), false);
+});
+
+test('Korean pipeline requires an explicit locale and its own inventory before
planning', () => {
+ const {pipelineLocale, inventoryBaseline, loadConfig} =
require('../state.cjs');
+ assert.throws(() => pipelineLocale(root, ''), /Set I18N_LOCALE/);
+ assert.equal(pipelineLocale(root, 'ja'), 'ja');
+ assert.equal(pipelineLocale(root, 'ko'), 'ko');
+ // A language declaration never substitutes for a native inventory
baseline.
+ const empty = fs.mkdtempSync(path.join(os.tmpdir(),
'doris-ko-inventory-'));
+ try {assert.throws(() => inventoryBaseline(empty, 'ko'), /Expected one ko
inventory snapshot, found 0/);}
+ finally {fs.rmSync(empty, {recursive: true, force: true});}
+ const settings = loadConfig(root).locales.ko;
+ const script = new RegExp(settings.scriptPattern, 'u');
+ for (const text of ['한국어 데이터베이스', 'ᄒ', 'ㄱ']) assert(script.test(text));
+ for (const text of ['English SQL', '日本語 データベース'])
assert(!script.test(text));
});
diff --git a/scripts/i18n/__tests__/state.test.cjs
b/scripts/i18n/__tests__/state.test.cjs
index ba3dd4c64a5..4f0c487bb86 100644
--- a/scripts/i18n/__tests__/state.test.cjs
+++ b/scripts/i18n/__tests__/state.test.cjs
@@ -7,8 +7,8 @@ const {execFileSync} = require('node:child_process');
const {hash, identity, decide, loadRecords, loadRecordsAt, stateFileFor} =
require('../state.cjs');
const {structure, alignHeadings} = require('../structure.cjs');
-test('Japanese version messages match the custom banner interpolation
contract', () => {
- const dictionary = require('../../../i18n/ja/code.json');
+for (const locale of ['ja', 'ko']) test(`${locale} version messages match the
custom banner interpolation contract`, () => {
+ const dictionary = require(`../../../i18n/${locale}/code.json`);
const variables = key =>
[...dictionary[key].message.matchAll(/\{(\w+)\}/g)].map(match =>
match[1]).sort();
assert.deepEqual(variables('theme.docs.versions.unreleasedVersionLabel'),
['unreleased']);
assert.deepEqual(variables('theme.docs.versions.latestVersionSuggestionLabel'),
['v21Link', 'v3xLink', 'v4xLink']);
diff --git a/scripts/i18n/__tests__/t04.test.cjs
b/scripts/i18n/__tests__/t04.test.cjs
index b2eb9ef6eae..4c1a6c5657d 100644
--- a/scripts/i18n/__tests__/t04.test.cjs
+++ b/scripts/i18n/__tests__/t04.test.cjs
@@ -28,9 +28,9 @@ test('PR build scope separates content locales, shared
inputs, and retired versi
assert.deepEqual(stateOnly.locales,['ja']);
assert.equal(stateOnly.docs_versions,'4.x');
assert.deepEqual(stateOnly.json,[shard]);
-
assert.deepEqual(buildScope(['sidebars.ts'],versions).locales,['en','zh-CN','ja']);
-
assert.deepEqual(buildScope(['.github/workflows/cron-deploy-website.yml'],versions).locales,['en','zh-CN','ja']);
-
assert.deepEqual(buildScope(['.github/workflows/manual-deploy-website.yml'],versions).locales,['en','zh-CN','ja']);
+
assert.deepEqual(buildScope(['sidebars.ts'],versions).locales,['en','zh-CN','ja','ko']);
+
assert.deepEqual(buildScope(['.github/workflows/cron-deploy-website.yml'],versions).locales,['en','zh-CN','ja','ko']);
+
assert.deepEqual(buildScope(['.github/workflows/manual-deploy-website.yml'],versions).locales,['en','zh-CN','ja','ko']);
assert.equal(buildScope(['versions.json'],versions).need_full_build,true);
assert.deepEqual(buildScope(['versioned_docs/version-1.2/a.md'],versions).retired,['1.2']);
// Only a managed locale renders dictionary changes, so only its dictionary
@@ -50,7 +50,7 @@ test('publication changes exercise the complete optimized
artifact on CI', () =>
assert.equal(scope.optimize_publish,true,file);
assert.equal(scope.docs_versions,'',file);
assert.equal(scope.need_full_build,true,file);
- assert.deepEqual(scope.locales,['en','zh-CN','ja']);
+ assert.deepEqual(scope.locales,['en','zh-CN','ja','ko']);
}
assert.equal(buildScope(['docs/example.md'],versions).optimize_publish,false);
});
@@ -167,18 +167,18 @@ test('source-only edits report stale Japanese content;
edited stale targets are
const page =
{pluginId:'default',version:'current',docId:'test',locale:'ja',status:'stale_unknown',
sourcePath:'docs/test.md',targetPath:'i18n/ja/docusaurus-plugin-content-docs/current/getting-started/intro.mdx'};
const root = path.resolve(__dirname,'../../..');
- const sourceEdit = await
checkTranslations({root,pages:[page],files:['docs/test.md'],records:new Map()});
+ const sourceEdit = await
checkTranslations({root,locale:'ja',pages:[page],files:['docs/test.md'],records:new
Map()});
assert.equal(sourceEdit.checked,0);
assert.deepEqual(sourceEdit.errors,[]);
- const targetEdit = await
checkTranslations({root,pages:[page],files:[page.targetPath],records:new
Map()});
+ const targetEdit = await
checkTranslations({root,locale:'ja',pages:[page],files:[page.targetPath],records:new
Map()});
assert.equal(targetEdit.checked,1);
assert.match(targetEdit.errors[0].message,/current source\/state/);
});
-test('required legacy link gate follows Japanese fallback in the same
version', () => {
+test('required legacy link gate follows managed locale fallback in the same
version', () => {
const {existingLocalTarget} = require('../../check_move.js');
- for (const version of ['current','version-4.x']) {
- const file =
`i18n/ja/docusaurus-plugin-content-docs/${version}/getting-started/what-is-apache-doris.md`;
+ for (const locale of ['ja', 'ko']) for (const version of
['current','version-4.x']) {
+ const file =
`i18n/${locale}/docusaurus-plugin-content-docs/${version}/getting-started/what-is-apache-doris.md`;
assert.equal(existingLocalTarget(file,'../ai/ai-overview.md'),true);
assert.equal(existingLocalTarget(file,'../ai/not-a-page-t04.md'),false);
}
diff --git a/translations/config.json b/translations/config.json
index 9b295bc63bf..3dfb5bd67c6 100644
--- a/translations/config.json
+++ b/translations/config.json
@@ -11,6 +11,17 @@
"docs/4.x": "4.x ドキュメント",
"community": "コミュニティ"
}
+ },
+ "ko": {
+ "sourceLocale": "en",
+ "sourceOverrides": [],
+ "languageName": "Korean",
+ "scriptPattern": "[\\u1100-\\u11ff\\u3130-\\u318f\\uac00-\\ud7af]",
+ "searchContextLabels": {
+ "docs/dev": "Dev 문서",
+ "docs/4.x": "4.x 문서",
+ "community": "커뮤니티"
+ }
}
}
}
diff --git a/translations/glossary/ko.json b/translations/glossary/ko.json
new file mode 100644
index 00000000000..2dc113efe50
--- /dev/null
+++ b/translations/glossary/ko.json
@@ -0,0 +1,69 @@
+{
+ "schemaVersion": 1,
+ "version": "1",
+ "keep": [
+ "Apache Doris",
+ "Doris",
+ "SelectDB",
+ "FE",
+ "BE",
+ "SQL",
+ "DDL",
+ "DML",
+ "NULL",
+ "Catalog",
+ "Stream Load",
+ "Routine Load",
+ "JSON",
+ "CSV",
+ "HDFS",
+ "S3",
+ "JDBC",
+ "MySQL",
+ "PostgreSQL"
+ ],
+ "keepReasons": {
+ "Apache Doris": "Product name",
+ "Doris": "Product name",
+ "SelectDB": "Company and product name",
+ "FE": "Frontend process identifier",
+ "BE": "Backend process identifier",
+ "SQL": "Query language acronym",
+ "DDL": "SQL statement category",
+ "DML": "SQL statement category",
+ "NULL": "SQL literal",
+ "Catalog": "Doris connector object name",
+ "Stream Load": "Load method name",
+ "Routine Load": "Load method name",
+ "JSON": "Data format name",
+ "CSV": "Data format name",
+ "HDFS": "Storage system name",
+ "S3": "Storage service name",
+ "JDBC": "Driver interface name",
+ "MySQL": "Database and protocol name",
+ "PostgreSQL": "Database name"
+ },
+ "terms": [
+ {
+ "source": "table",
+ "target": "테이블"
+ },
+ {
+ "source": "database",
+ "target": "데이터베이스"
+ },
+ {
+ "source": "load",
+ "target": "데이터 적재"
+ },
+ {
+ "source": "query",
+ "target": "쿼리"
+ },
+ {
+ "source": "materialized view",
+ "target": "구체화된 뷰",
+ "required": true
+ }
+ ]
+}
diff --git a/translations/scope/ko.json b/translations/scope/ko.json
new file mode 100644
index 00000000000..93ad2f64ca4
--- /dev/null
+++ b/translations/scope/ko.json
@@ -0,0 +1,27 @@
+{
+ "schemaVersion": 1,
+ "locale": "ko",
+ "maxBatchPages": 20,
+ "groups": [
+ {
+ "id": "DEV",
+ "pluginId": "default",
+ "version": "current",
+ "sourceRoot": "docs"
+ },
+ {
+ "id": "4X",
+ "pluginId": "default",
+ "version": "4.x",
+ "sourceRoot": "versioned_docs/version-4.x"
+ },
+ {
+ "id": "COMMUNITY",
+ "pluginId": "community",
+ "version": "current",
+ "sourceRoot": "community"
+ }
+ ],
+ "retainEnglish": [],
+ "retainSidebarLabels": []
+}
diff --git a/translations/state/ko/docs.json b/translations/state/ko/docs.json
new file mode 100644
index 00000000000..f2350ea8816
--- /dev/null
+++ b/translations/state/ko/docs.json
@@ -0,0 +1,4 @@
+{
+ "schemaVersion": 1,
+ "pages": []
+}
diff --git a/translations/state/ko/pages/community/current/join-community.json
b/translations/state/ko/pages/community/current/join-community.json
new file mode 100644
index 00000000000..078d7a37e02
--- /dev/null
+++ b/translations/state/ko/pages/community/current/join-community.json
@@ -0,0 +1,20 @@
+{
+ "schemaVersion": 1,
+ "page": {
+ "pluginId": "community",
+ "version": "current",
+ "docId": "join-community",
+ "locale": "ko",
+ "sourceLocale": "en",
+ "sourcePath": "community/join-community.md",
+ "targetPath":
"i18n/ko/docusaurus-plugin-content-docs-community/current/join-community.md",
+ "sourceCommit": "c1dc0ada58258822db4f31d9f05b11cf3e011b7b",
+ "sourceHash":
"c0fb07e339e759ca4bf071efabafb60ecb13e1978173dc88e3de79e7a32949b9",
+ "sourceTechnicalHash":
"7ba43a16e4a34f5071e5c95fdef1a9db9511fee84628708975f6e450281845db",
+ "targetHash":
"12663afee635fe283e4bfde370320a7807b2c4fe4860776c9bd7246f1b8fb8cd",
+ "reviewStatus": "machine",
+ "ownership": "machine",
+ "translatedAt": "2026-10-18T11:36:50.152Z",
+ "glossaryVersion": "1"
+ }
+}
diff --git
a/translations/state/ko/pages/default/4.x/getting-started/what-is-apache-doris.json
b/translations/state/ko/pages/default/4.x/getting-started/what-is-apache-doris.json
new file mode 100644
index 00000000000..4803cbd1896
--- /dev/null
+++
b/translations/state/ko/pages/default/4.x/getting-started/what-is-apache-doris.json
@@ -0,0 +1,20 @@
+{
+ "schemaVersion": 1,
+ "page": {
+ "pluginId": "default",
+ "version": "4.x",
+ "docId": "getting-started/what-is-apache-doris",
+ "locale": "ko",
+ "sourceLocale": "en",
+ "sourcePath":
"versioned_docs/version-4.x/getting-started/what-is-apache-doris.md",
+ "targetPath":
"i18n/ko/docusaurus-plugin-content-docs/version-4.x/getting-started/what-is-apache-doris.md",
+ "sourceCommit": "c1dc0ada58258822db4f31d9f05b11cf3e011b7b",
+ "sourceHash":
"c1b950ba12598be8495190f93fd341dd646d98c837bf09c72ccc199c2ebb941e",
+ "sourceTechnicalHash":
"2c3ee90a60bae82e00653c8a088e174bf2ecd6eb8ce1bdda96d08cc50a160318",
+ "targetHash":
"84035c152f94daaaec760b5529365ed8f235aa5933b4904395276163d1c2db41",
+ "reviewStatus": "machine",
+ "ownership": "machine",
+ "translatedAt": "2026-10-18T11:36:50.077Z",
+ "glossaryVersion": "1"
+ }
+}
diff --git
a/translations/state/ko/pages/default/current/getting-started/intro.json
b/translations/state/ko/pages/default/current/getting-started/intro.json
new file mode 100644
index 00000000000..6335bd2036d
--- /dev/null
+++ b/translations/state/ko/pages/default/current/getting-started/intro.json
@@ -0,0 +1,20 @@
+{
+ "schemaVersion": 1,
+ "page": {
+ "pluginId": "default",
+ "version": "current",
+ "docId": "getting-started/intro",
+ "locale": "ko",
+ "sourceLocale": "en",
+ "sourcePath": "docs/getting-started/intro.mdx",
+ "targetPath":
"i18n/ko/docusaurus-plugin-content-docs/current/getting-started/intro.mdx",
+ "sourceCommit": "c1dc0ada58258822db4f31d9f05b11cf3e011b7b",
+ "sourceHash":
"5c870a2583db46c203dcd610b575d3888bf2ba442e41a58a8acb7177d9db4abe",
+ "sourceTechnicalHash":
"691b2315e50a90059f94a53fe7ffa14602ebfe5d0069d69053bf44580d12aa42",
+ "targetHash":
"6920826b38eb7d45562f44f48f3de311a5c2f84365a48d5a0a093882424e3c99",
+ "reviewStatus": "machine",
+ "ownership": "machine",
+ "translatedAt": "2026-10-18T11:36:49.982Z",
+ "glossaryVersion": "1"
+ }
+}
diff --git
a/translations/state/ko/pages/default/current/getting-started/what-is-apache-doris.json
b/translations/state/ko/pages/default/current/getting-started/what-is-apache-doris.json
new file mode 100644
index 00000000000..163bef7ba09
--- /dev/null
+++
b/translations/state/ko/pages/default/current/getting-started/what-is-apache-doris.json
@@ -0,0 +1,20 @@
+{
+ "schemaVersion": 1,
+ "page": {
+ "pluginId": "default",
+ "version": "current",
+ "docId": "getting-started/what-is-apache-doris",
+ "locale": "ko",
+ "sourceLocale": "en",
+ "sourcePath": "docs/getting-started/what-is-apache-doris.md",
+ "targetPath":
"i18n/ko/docusaurus-plugin-content-docs/current/getting-started/what-is-apache-doris.md",
+ "sourceCommit": "c1dc0ada58258822db4f31d9f05b11cf3e011b7b",
+ "sourceHash":
"c1b950ba12598be8495190f93fd341dd646d98c837bf09c72ccc199c2ebb941e",
+ "sourceTechnicalHash":
"2c3ee90a60bae82e00653c8a088e174bf2ecd6eb8ce1bdda96d08cc50a160318",
+ "targetHash":
"84035c152f94daaaec760b5529365ed8f235aa5933b4904395276163d1c2db41",
+ "reviewStatus": "machine",
+ "ownership": "machine",
+ "translatedAt": "2026-10-18T11:36:49.892Z",
+ "glossaryVersion": "1"
+ }
+}
diff --git a/translations/state/ko/resolved-deletions.json
b/translations/state/ko/resolved-deletions.json
new file mode 100644
index 00000000000..22890804fd1
--- /dev/null
+++ b/translations/state/ko/resolved-deletions.json
@@ -0,0 +1,4 @@
+{
+ "schemaVersion": 1,
+ "deletions": []
+}
diff --git a/translations/state/ko/shards.schema.json
b/translations/state/ko/shards.schema.json
new file mode 100644
index 00000000000..95abdd99357
--- /dev/null
+++ b/translations/state/ko/shards.schema.json
@@ -0,0 +1,4 @@
+{
+ "schemaVersion": 1,
+ "format": "page-record-v1"
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]