hasCJKLanguage 한 줄에 단어 수가 세 배, 요약은 한 문단으로 줄었습니다
Hugo에는 글마다 단어 수(.WordCount), 읽는 데 걸리는 분(.ReadingTime), 앞부분 요약(.Summary)을 계산해 주는 기능이 있습니다.
한국어 블로그라면 설정에 hasCJKLanguage = true를 넣으라는 안내를 자주 봅니다.
CJK는 중국어·일본어·한국어를 묶어 부르는 말입니다.

그런데 이걸 켜면 숫자가 얼마나 바뀌는지는 적어 둔 곳을 못 찾았습니다.
그래서 제 블로그에 공개된 글 12편을 끈 채로 한 번, 켠 채로 한 번 빌드해서 값을 전부 뽑아 비교했습니다.
Hugo v0.165.0 extended이고 2026-10-04에 잰 값입니다.
공개 글 12편을 두 번 빌드해 CSV로 뽑았습니다

운영 중인 저장소는 건드리지 않고 사본을 떠서 했습니다. 홈 페이지에 CSV 출력 형식을 하나 더 붙이고, 그 템플릿에서 글마다 값을 한 줄씩 찍게 했습니다.
# lab/cfg/stats.toml — 원래 설정 위에 덧씌우는 파일
[outputFormats.stats]
mediaType = 'text/csv'
baseName = 'stats'
isPlainText = true
notAlternative = true
[outputs]
home = ['html', 'rss', 'stats']
{{/* layouts/home.stats.csv — 실제로 뽑은 열 중 이 글에 쓴 것만 남김 */}}
{{ range where site.RegularPages "Section" "posts" -}}
{{ .Slug }},{{ .WordCount }},{{ .ReadingTime }},{{ countrunes .Plain }},{{ countrunes (.Summary | plainify) }},{{ len (findRE `<p>` (string .Summary)) }}
{{ end -}}
countrunes는 공백을 뺀 글자 수를 셉니다. 켜고 끄는 건 설정 파일을 하나 더 덧씌워서 처리했습니다.
$ hugo --quiet --config hugo.toml,lab/cfg/stats.toml -d lab/out-off # 꺼짐
$ hugo --quiet --config hugo.toml,lab/cfg/stats.toml,lab/cfg/cjk.toml -d lab/out-on # 켜짐 (cjk.toml: hasCJKLanguage = true 한 줄)
제 사이트의 요약 길이 설정은 summaryLength = 40입니다. 아래 숫자는 모두 이 값 기준입니다.
단어 수는 세 배 가까이 되지만 고르게 늘지는 않습니다

12편의 단어 수 합계는 14,880에서 42,329로 늘었습니다. 글별로 보면 2.50배에서 3.16배까지 퍼져 있습니다.
| 글 | 공백 뺀 글자 | 단어(꺼짐) | 단어(켜짐) | 배율 | 읽는 시간 꺼짐→켜짐 |
|---|---|---|---|---|---|
| 1 | 3,924 | 1,070 | 2,804 | 2.62 | 6 → 6분 |
| 2 | 3,967 | 957 | 2,992 | 3.13 | 5 → 6분 |
| 3 | 4,210 | 1,205 | 3,602 | 2.99 | 6 → 8분 |
| 4 | 4,259 | 1,033 | 2,698 | 2.61 | 5 → 6분 |
| 5 | 4,342 | 1,127 | 3,456 | 3.07 | 6 → 7분 |
| 6 | 4,373 | 1,164 | 3,661 | 3.15 | 6 → 8분 |
| 7 | 4,547 | 1,172 | 3,709 | 3.16 | 6 → 8분 |
| 8 | 4,665 | 1,202 | 3,006 | 2.50 | 6 → 6분 |
| 9 | 4,730 | 1,170 | 3,120 | 2.67 | 6 → 7분 |
| 10 | 4,910 | 1,401 | 3,664 | 2.62 | 7 → 8분 |
| 11 | 5,533 | 1,419 | 4,158 | 2.93 | 7 → 9분 |
| 12 | 7,183 | 1,960 | 5,459 | 2.79 | 10 → 11분 |
꺼져 있을 때 단어는 띄어쓰기로 나눈 덩어리입니다. 한국어로 치면 어절 수에 가깝습니다. 켜면 세는 방식이 바뀌는데, 한 줄짜리 글로 시험해 보니 규칙이 바로 보였습니다.
문장 꺼짐 켜짐
Hugo Cloudflare Pages 3 3
Hugo의 설정을 바꿨습니다. 3 14
hasCJKLanguage를 켰습니다 2 19
띄어쓰기로 나눈 덩어리에 한글이 한 글자라도 섞이면 그 덩어리의 글자를 전부 셉니다.
영문 글자와 마침표까지 셉니다. 한글이 없는 덩어리는 길어도 1입니다.
그래서 hasCJKLanguage를처럼 영어 뒤에 조사가 붙으면 그 한 덩어리가 15단어가 됩니다.
Hugo v0.165.0 소스의 단어 세는 부분도 그렇게 되어 있습니다. 덩어리의 바이트 길이와 글자 수가 같으면(ASCII만 있으면) 1, 다르면 글자 수를 더합니다. 그래서 엄밀히는 한글뿐 아니라 ASCII가 아닌 글자가 하나라도 섞인 덩어리가 모두 이렇게 세어집니다 —
hugolib/page__content.go.
배율이 2.50으로 가장 낮은 8번 글은 설정 키·인라인 코드처럼 영어로만 된 덩어리가 많은 글입니다. 마크다운 원문을 띄어쓰기로 나눠 보니 1,365개 중 348개(약 25%)가 ASCII만으로 된 덩어리였습니다. 이런 덩어리는 켜도 1로 남으니 덜 늘어납니다. 다만 이 비율만으로 배율 순서가 그대로 설명되지는 않았습니다.
읽는 시간은 0~2분 늘었고 글 사이 순서가 바뀝니다

공식 문서는 읽는 속도를 분당 212단어, CJK일 때 분당 500단어로 잡는다고 적고 있습니다. 실제 계산식은 소스에 이렇게 되어 있습니다.
if isCJKLanguage {
result.readingTime = (result.wordCount + 500) / 501
} else {
result.readingTime = (result.wordCount + 212) / 213
}
12편 값이 전부 이 식과 맞았습니다. 반면 “500으로 나눠 올림"으로 계산하면 8번 글이 어긋납니다. 3,006 ÷ 500 = 6.012라 올림하면 7분인데 Hugo가 낸 값은 6분입니다. 직접 계산해서 화면 값과 맞춰 보려면 위 식을 써야 합니다.
늘어난 폭은 0분이 2편, 1분이 6편, 2분이 4편이었습니다. 걸리는 건 순서입니다. 꺼져 있을 때는 6번·7번·8번이 모두 6분이었는데, 켜면 6번·7번은 8분, 8번은 그대로 6분입니다. 셋 중 글자 수는 8번이 가장 많은데, 켠 뒤 읽는 시간은 가장 짧게 나옵니다. 앞에서 본 영어 덩어리가 1로만 세어지는 영향입니다.
어느 쪽 숫자가 실제로 읽는 시간에 더 가까운지는 재 보지 않았습니다. 여기서 확인한 것은 설정 하나로 숫자가 얼마나 움직이는가까지입니다.
요약 길이를 정하는 건 설정보다 첫 문단이었습니다

요약은 더 크게 바뀌었습니다. 공백 뺀 글자 수로 쟀습니다.
| 요약에 든 문단 | 요약 글자 수(최소~최대) | |
|---|---|---|
| 꺼짐 | 1~3개 | 116~264자 |
| 켜짐 | 모두 1개 | 45~202자 |
12편 중 9편이 꺼짐에서 2~3문단이던 요약이 켜짐에서 1문단으로 줄었습니다.
Hugo의 자동 요약은 글자 수로 자르지 않고 문단 단위로 붙입니다.
첫 문단부터 단어를 세어 가다가 누적이 summaryLength에 닿은 문단에서 끝냅니다.
설정 문서의 표현은 “문단 경계에서 자르되 최소 이만큼의 단어"입니다.
꺼짐에서 40은 40어절이라 첫 문단이 40어절이 안 되는 글은 다음 문단까지 붙고(12편 중 9편)
켜짐에서 40은 사실상 40글자라 첫 문단에서 바로 끝납니다.
그럼 남은 편차는 어디서 왔을까요. 켜짐 쪽은 12편 모두 한 문단짜리 요약인데도 45자에서 202자까지 벌어집니다.
이건 설정이 아니라 각 글의 첫 문단 길이 차이입니다.
summaryLength를 바꿔 가며 다시 뽑아 봐도 이 구조가 보입니다.
| summaryLength | 꺼짐: 문단 / 글자 수 중앙값 | 켜짐: 문단 / 글자 수 중앙값 |
|---|---|---|
| 10 | 1개 / 108.5자 | 1개 / 108.5자 |
| 40 | 1~3개 / 191자 | 1개 / 108.5자 |
| 70 | 2~4개 / 238.5자 | 1~2개 / 113.5자 |
| 150 | 3~8개 / 541.5자 | 1~3개 / 197.5자 |
| 300 | 5~13개 / 1,096.5자 | 3~5개 / 382자 |
켜짐에서 10과 40은 결과가 똑같습니다. 12편의 첫 문단이 모두 40글자를 넘기 때문입니다. 값을 올려도 요약은 매끄럽게 길어지지 않고 문단 하나씩 계단처럼 뜁니다.
하나 더 있습니다. 단어를 세는 건 <p> 문단뿐인데, 그 사이에 낀 제목·표·이미지는 세지 않고 요약에 함께 딸려 들어갑니다.
꺼짐에 summaryLength = 150으로 뽑았을 때 한 글의 요약에 <h2> 1개, 표 1개, 이미지 2장이 들어 있었고 글자 수가 1,002자였습니다.
켜짐에서는 문단 끝 글자 하나가 덜 세어집니다. 공백 없는 40글자 문단으로 시험하니 summaryLength = 39에서는 한 문단, 40에서는 두 문단이 됐습니다. 꺼짐에서는 10어절 문단이 10에서 한 문단으로 끝났습니다. 경계에 딱 맞춰 값을 잡을 때만 신경 쓰면 되는 차이입니다 —
resources/page/page_markup.go의 ExtractSummaryFromHTML.
요약을 안 쓴다고 적어 뒀는데 RSS가 쓰고 있었습니다

제 설정 파일에는 summaryLength = 40 위에 “요약을 자동 생성하지 않고 front matter의 description을 쓴다"는 주석이 달려 있습니다.
실제로 화면 템플릿 어디에도 .Summary는 없습니다.
그런데 RSS 템플릿을 따로 만들지 않았으니 Hugo에 들어 있는 기본 템플릿이 쓰입니다. 그 템플릿의 한 줄이 이렇습니다.
<description>{{ .Summary | transform.XMLEscape | safeHTML }}</description>
라이브 피드를 받아 사본 빌드와 맞춰 봤습니다.
피드 항목 13개 중 description 안에 <img> 가 있는 항목
꺼짐(지금 라이브와 같음) 9개
켜짐 0개
라이브 피드 13개 항목의 description은 꺼짐 빌드와 길이가 전부 같았습니다.
제 글은 첫 문단 바로 아래에 이미지를 두는데, 꺼짐에서는 요약이 둘째 문단까지 가면서 그 이미지가 피드에 같이 실리고 있었습니다.
켜면 요약이 첫 문단에서 끝나니 이미지가 모두 빠집니다.
hasCJKLanguage 한 줄이 화면에 안 보이는 피드 내용까지 바꿉니다.
이 설정을 다시 정한다면

제 사이트 설정은 아직 그대로입니다. 다시 정한다면 이 순서로 보겠습니다.
- 템플릿에서
.WordCount·.ReadingTime·.Summary를 어디서 쓰는지부터 찾습니다. 내장 RSS처럼 직접 안 만든 템플릿도 셉니다. - 읽는 시간을 화면에 띄운다면
hasCJKLanguage를 켭니다. 꺼 두면 어절 수를 분당 212로 나누게 됩니다. 영어 덩어리가 많은 글이 짧게 나오는 쏠림은 남습니다. - 켰다면
summaryLength는 글자 수에 가까운 값으로 다시 잡습니다. 같은 40이라도 뜻이 달라집니다. 제 12편에서는 꺼짐 40과 켜짐 150의 요약 글자 수 중앙값이 191자와 197.5자로 비슷했습니다. - 요약 길이를 글마다 일정하게 맞춰야 한다면 숫자로는 안 됩니다. 첫 문단 길이를 따라가기 때문입니다. front matter의
summary나 본문의 `
구분선을 쓰면 자동 요약보다 우선합니다([요약 문서](https://gohugo.io/content-management/summaries/)). 시험해 보니summary에 적은 문장이 그대로 요약이 됐고 앞까지가 요약이 됐습니다. 5. 특정 글만 다르게 세야 하면 그 글의 front matter에isCJKLanguage를 둡니다. 전체 설정을 끈 채로 한 글에만 isCJKLanguage: true`를 주니 그 글만 단어 수가 30에서 120으로 바뀌었습니다.
바꾸고 나면 빌드를 한 번씩 더 돌려서 피드까지 봅니다. 이번에 화면에 안 보이는 곳이 제일 많이 바뀌었습니다.