본문으로 건너뛰기

누락 글리프 검사 · 현지화 텍스트와 비트맵 폰트 비교

한국어·일본어 빌드에서 글자 대신 네모가 나오기 전에, 현지화 파일의 텍스트와 BMFont에 실제로 있는 글리프를 비교하세요.

한국어·일본어 글자가 있어야 할 자리에 네모(□)나 빈칸이 보이면 폰트에 그 코드 포인트의 글리프가 없다는 뜻입니다. 비트맵 폰트에는 구울 때 넣은 글자만 있고, .fnt에 글리프마다 char id= 줄이 하나씩 있습니다. 검사기는 .po(msgstr 값), .json, .csv·.tsv, .txt에서 번역문을 꺼내 서로 다른 글자 하나하나를 .fnt(또는 UI 랩 폰트 단계에서 만든 폰트)와 비교하고, 빠진 글자마다 유니코드 코드 포인트·사용 횟수·처음 나오는 줄을 보여 줍니다. TTF의 문자 표는 아직 읽지 못합니다.

UI 패널·버튼·글리프 시트·UI 시트(PNG)를 끌어다 놓으세요
UI 랩 열기
브라우저에서 처리하며 파일은 업로드되지 않습니다.
UI 랩: 나인 슬라이스 가이드와 여러 크기 미리보기가 있는 CC0 UI 패널
CC0 에셋(Kenney)을 연 실제 UI 랩 화면입니다.
출력
  • Nine-slice측정 확인· Pillow
  • Bitmap font측정 확인· independent .fnt parser
  • Button states측정 확인· Pillow
  • Engine import미검증

글자가 네모로 바뀌는 이유

모든 글자는 유니코드 코드 포인트이고 BMFont는 이를 10진수로 저장합니다. 시는 U+C2DC이며 .fnt에는 char id=49884로 적힙니다. 검사는 단순한 집합 비교입니다. 텍스트에 쓰인 서로 다른 글자에서 폰트의 char id 값을 빼면 됩니다. 문자 체계가 크기 때문에 한국어·일본어 게임 폰트는 실제로 쓰는 문자열로 만듭니다. 완성형 한글 음절 U+AC00~U+D7A3은 11,172개 코드 포인트이고, 한중일 통합 한자 블록 U+4E00~U+9FFF는 20,992개에 이릅니다.

흔한 원인은 폰트를 구운 뒤 갱신된 번역, 원문 언어로 만든 폰트, 모양은 같지만 코드 포인트가 다른 글자(전각 ! U+FF01과 ! U+0021), 그리고 분해된 한글입니다. 분해형에서는 가가 음절 하나(U+AC00)가 아니라 자모 U+1100 U+1161로 들어옵니다. 검사기는 코드 포인트를 정확히 비교하므로 이것들을 모두 보고합니다.

파일마다 무엇을 읽는지가 중요합니다. .po에서는 msgstr(와 msgstr[n]) 값만 읽고 원문 키 msgid는 읽지 않지만, 헤더 항목의 msgstr(Language:, Content-Type:)도 텍스트로 셉니다. JSON은 모든 문자열 값, CSV·TSV는 키와 원문 열을 포함한 모든 칸을 읽습니다. 줄 바꿈 없는 공백 U+00A0, 전각 공백 U+3000을 포함한 공백 문자는 글리프로 그리지 않으므로 건너뜁니다.

예시: 한국어 .po와 글리프 4개짜리 .fnt

폰트는 시·작·끝·내로 구웠습니다. 이 파일에 대해 검사기가 돌려주는 결과입니다.

ko.po (9줄)                             font.fnt (글리프 4개)
msgid ""                                char id=49884   시 U+C2DC
msgstr ""                               char id=51089   작 U+C791
"Language: ko\n"                        char id=45149   끝 U+B05D
msgid "Start"  →  msgstr "시작"         char id=45236   내 U+B0B4
msgid "Quit"   →  msgstr "끝내기"

검사한 텍스트  "Language: ko" / "시작" / "끝내기"   (msgid 값은 읽지 않음)
빠진 글자      기 U+AE30 ×1   (텍스트 5번 줄)
               a ×2, g ×2, :, L, e, k, n, o, u   (헤더 항목, 텍스트 2번 줄)
추가할 것      기 = 0xAE30 = 44592 → 다시 만든 폰트에 "char id=44592" 필요

라틴 문자는 번역이 아니라 헤더 항목에서 나왔습니다. 폰트에 ASCII를 넣거나(대부분의 게임은 어차피 숫자와 라틴 문자가 필요함) 그 줄들을 무시하세요. 여기서 진짜로 빠진 글자는 기입니다.

검사하는 텍스트는 어디서 오나

파일읽는 것무시하는 것
.pomsgstr와 msgstr[n] 값, 이어지는 줄 포함(헤더 항목도 포함)msgid, msgctxt, 주석
.json깊이에 상관없이 모든 문자열 값객체 키, 숫자, 불리언
.csv / .tsv모든 행의 모든 칸(머리글 행과 키 열 포함)구분자와 따옴표
.txt 또는 붙여 넣은 텍스트전부줄 바꿈과 그 밖의 공백
.fnt(글리프 출처)모든 char 줄의 id커닝, 페이지, 수치

이렇게 작동합니다

  • .po(msgstr 값), JSON(모든 문자열 값), CSV·TSV(모든 칸), 일반 텍스트를 읽습니다.
  • .fnt의 글리프 목록이나 랩의 폰트 단계에서 만든 폰트와 비교합니다.
  • 빠진 글자마다 개수와 처음 나오는 줄 번호.
  • missing-glyphs.json과 폰트 도구에 붙여 넣을 목록을 내려받습니다.

사용 방법

  1. 글리프 출처(.fnt 또는 랩의 폰트)를 고릅니다.
  2. 현지화 파일을 넣거나 텍스트를 붙여 넣습니다.
  3. 빠진 글자 목록을 읽습니다.
  4. 보고서를 내보냅니다.

결과 확인

  • 글자를 추가하고 폰트를 다시 만든 뒤 검사를 다시 돌립니다. 빠진 것이 없다고 나오고, 검사한 서로 다른 글자 수가 표시돼야 합니다.
  • missing-glyphs.json을 엽니다. 항목마다 char, U+XXXX 형식의 codepoint, count, lines가 있고, missing-glyphs.txt는 같은 글자를 한 줄로 모아 폰트 도구의 문자 칸에 바로 붙여 넣을 수 있습니다.
  • 게임에서 언어 파일의 모든 글자가 든 시험 문자열을 하나 띄웁니다. 네모나 빈칸이 하나도 없어야 합니다.

문제 해결

증상유력한 원인확인 방법해결
한국어·일본어 .po인데 라틴 문자(L, a, n, g…)가 빠졌다고 나옴헤더 항목의 msgstr(Language:, Content-Type:)를 텍스트로 읽음줄 번호가 꺼낸 텍스트의 첫 줄들을 가리킴폰트에 ASCII를 넣거나 그 줄들을 무시
CSV의 영어 원문 열이 보고됨키·원문 열을 포함해 CSV·TSV의 모든 칸을 읽음빠진 글자 대부분이 라틴 문자이고 모든 줄에 나옴대상 언어 열만 내보내거나 그 텍스트를 붙여 넣기
있어 보이는 글자가 빠졌다고 나옴코드 포인트가 다른 닮은 글자(전각 !, ~, 다른 대시)보고서의 U+ 코드와 .fnt의 id 비교그 코드 포인트를 폰트에 추가하거나, 내보내기 전에 텍스트를 정규화
폰트에 있는 한글 음절이 빠졌다고 나옴텍스트가 분해형이라 음절 대신 자모 U+1100~U+11FF보고서에 U+11xx 코드가 나열됨현지화 파이프라인에서 문자열을 NFC로 정규화
빠진 글자는 없는데 게임에 여전히 네모가 나옴게임이 검사한 .fnt와 다른 폰트·굵기로 그리거나, UI 랩 폰트를 폰트 파일 모드로 만들어 TTF에 없는 글자를 브라우저 대체 폰트가 그린 채로 구움빌드에 실제로 들어가는 .fnt 확인, 글리프 시트에서 모양이 다른 글자 찾기실제 배포하는 .fnt로 검사. Godot에서는 BMFont 가져오기 설정에 대체 폰트를 지정 가능
줄 번호가 파일과 맞지 않음원본 파일이 아니라 꺼낸 텍스트의 줄을 셈.po 보고서의 2번 줄이 헤더 텍스트임파일에서 그 글자 자체를 검색
TTF·OTF를 글리프 출처로 고를 수 없음이번 버전은 폰트의 cmap 표를 해석하지 않음—먼저 폰트로 .fnt를 만든 뒤 그것과 비교

출력 파일과 검증 방법

"측정 확인"은 내려받은 파일을 페이지 밖에서(Pillow·numpy·별도 파서) 다시 열어 그 속성을 측정했다는 뜻입니다. 게임 엔진에서 불러오는 것은 시험하지 않았습니다.

대상파일검증
Nine-slicenine-slice.json · previews · SETUP.md측정 확인 Pillow크기를 바꾼 모든 미리보기에서 네 모서리 블록을 늘이지 않습니다. Chromium에서는 바이트 동일, Firefox에서는 반투명 픽셀이 알파 반올림 한 단계만큼 다를 수 있습니다. 빈틈·겹침 0.
Bitmap fontfont.png · font.fnt (BMFont text) · font.json측정 확인 independent .fnt parser테스트에 따로 작성한 파서로 .fnt를 다시 읽어 헤더와 모든 글리프 영역이 일치했습니다.
Button statesstates/*.png · strip · states.json측정 확인 Pillownormal은 원본과 같습니다(Chromium에서는 바이트 동일, Firefox에서는 반투명 픽셀의 색이 알파 반올림 한 단계 이내). states.json의 모든 영역이 스트립에서 해당 상태를 정확히 잘라 냅니다.
Engine importGodot NinePatchRect · Unity Sprite border · BMFont import미검증Godot·Unity에서 실행하지 않았습니다.

검증 근거

나인 슬라이스 모서리가 100×40·300×80·800×200·420×120에서 늘어나지 않음, 동일한 열 12개에서 테두리 6·6·6·6 제안. 버튼 상태: normal이 원본과 같음, disabled는 알파 128 회색, focus 링 정확. .fnt 글리프 레코드가 JSON과 일치. .po의 누락 글리프를 정확히 나열. 흰 바탕 검정 글자 21:1 측정. 이미지는 브라우저 캔버스를 거칩니다. Chromium은 바이트가 그대로이고, Firefox는 반투명 픽셀의 색을 미리 곱한 값 한 단계로 반올림합니다(Kenney 버튼에서 측정: 알파 63에서 최대 4단계). 알파와 불투명 픽셀은 그대로입니다.

한계

  • 커닝 쌍 없음, 폰트 페이지 1장, MSDF 없음. SDF 출력은 베타입니다.
  • TTF의 cmap을 해석하지 않으므로 누락 글리프 점검에는 .fnt나 랩의 폰트가 필요합니다.
  • 아틀라스는 1페이지이고, 서로 닿은 요소는 하나로 셉니다.
  • Godot·Unity에서 렌더링해 보지 않았습니다. 엔진용 값(patch margin, L·B·R·T 테두리)은 문서 기준이며 엔진에서 시험하지 않았습니다.

버전과 출처

docs/UI-LAB.md를 위해 Chromium에서 측정했습니다. 글리프 4개짜리 .fnt로 .po를 검사하자 a 시 작 끝 내 기를 정확한 개수·줄 번호와 함께 보고했고, 폰트에 있는 가는 보고하지 않았습니다. 위 예시는 같은 함수로 다시 계산했으며, 헤더 항목 줄은 현재 파서의 동작 그대로입니다. .fnt 필드의 의미는 AngelCode BMFont 문서를, .po 구조는 GNU gettext 매뉴얼을 따릅니다.

참고한 공식 문서

자주 묻는 질문

TTF 폰트와 비교할 수 있나요?

아직 아닙니다. 이번 버전은 TTF의 cmap 표를 해석하지 않으므로 .fnt나 랩의 폰트를 쓰세요.

실제 파일로 확인했나요?

글리프 4개짜리 .fnt와 .po 파일을 비교해 빠진 글자 6개를 개수와 줄 번호까지 정확히 보고했습니다.

무료인가요? 계정이 필요한가요?

이 페이지의 기능은 모두 무료이며 계정 없이 쓸 수 있습니다. 워터마크나 막혀 있는 내보내기가 없습니다.

스프라이트가 업로드되나요?

아니요. Studio는 이 브라우저 탭 안에서 디코딩·패킹·내보내기를 합니다. 프로젝트는 브라우저(IndexedDB)에 자동 저장되며 .nerulio 파일로 저장할 수 있습니다.

Aseprite나 엔진 플러그인을 설치해야 하나요?

아니요. .aseprite 파일은 브라우저에서 읽고 씁니다. 엔진별 번들에는 그 엔진에 필요한 것이 들어 있습니다(Godot는 가져오기 설정과 씬, Unity와 Godot 타일셋은 작은 편집기 스크립트).