---
title: "짧은 글자일수록 번역에서 더 길어진다"
description: "언어가 바뀌면 글자 길이가 바뀌고 한국어에 맞춰 잡은 칸이 깨집니다. 얼마나 늘어나는지, 폰트에 없는 글자는 어떻게 되는지, 오른쪽에서 왼쪽으로 읽는 언어에서 화면이 어떻게 뒤집히는지를 봅니다."
author: "유니얼"
pubDate: 2026-09-17
category: "game-dev/unity/ui"
tags: ["Unity", "UI", "uGUI"]
canonical: https://blog.unialgames.com/posts/unity-ui-localization/
---
버튼 하나에 "확인" 두 글자가 들어갑니다. 칸은 그 두 글자에 딱 맞게 잡혀 있습니다.

영어판을 내면 거기에 `Confirm` 이 들어갑니다. 독일어판이면 `Bestätigen` 입니다. **칸은 그대로인데 글자만 길어집니다.**

다국어를 낼 계획이 조금이라도 있으면, 시안 단계에서 정해 둬야 할 것들이 있습니다.

## 짧을수록 더 늘어납니다

번역하면 길어진다는 것은 대체로 압니다. 덜 알려진 쪽은 **짧은 문구일수록 배율이 크다**는 것입니다.

W3C 의 「Text size in translation」 에 IBM 이 쓰던 예상 확장률이 실려 있습니다. 영어 원문 기준입니다.

| 원문 글자 수 | 번역 뒤 길이 |
| --- | --- |
| 10자 이하 | 200~300% |
| 11~20자 | 180~200% |
| 21~30자 | 160~180% |
| 31~50자 | 140~160% |
| 51~70자 | 150~170% |
| 70자 초과 | 130% |

문서의 요약은 한 줄입니다.

> the smaller the source message, the higher the likely translation length

긴 설명문은 1.3배쯤 늘어나고 끝납니다. 그런데 **버튼 라벨과 탭 이름과 아이콘 밑 한 단어가 두세 배**가 됩니다. 그리고 그것들이 하필 가장 좁은 칸에 들어 있습니다. 같은 문서가 그 지점을 이렇게 적었습니다.

> the smaller the English text, the more likely it is to be squeezed into a small space

직접 넣어 보시면 감이 빠릅니다.

<x-lang>
<script type="application/json">
{
  "label": "같은 문구가 언어마다 칸을 얼마나 먹는가",
  "default": { "phrase": 0, "lang": 2, "box": 0 },
  "note": "글자 너비는 브라우저가 실제로 잰 값입니다. 폰트가 다르면 배율도 조금 달라집니다."
}
</script>
</x-lang>

칸을 잡는 방식은 셋뿐입니다.

- **한국어에 딱 맞춤**: 가장 예뻐 보이고 가장 잘 깨집니다
- **가장 긴 언어에 맞춤**: 안 깨집니다. 대신 한국어판에서 칸이 헐렁합니다
- **내용만큼 늘어남**: 안 깨집니다. 대신 옆에 붙은 것들의 자리가 언어마다 달라집니다

셋 중에 무엇을 고를지는 **시안을 그리는 쪽에서 정하는 것**입니다. 늘어나는 칸으로 간다면 옆 요소가 밀려도 되는지, 줄바꿈을 허용할지, 두 줄이 되면 버튼 높이가 커져도 되는지까지 같이 정해 주셔야 합니다. 넘칠 때 잘리는지 줄어드는지는 [크기가 고정이고 꾸밈이 없으면 일반 Text 로 충분하다](/posts/unity-ui-text-vs-textmeshpro/)에 정리해 뒀습니다.

문서의 권고도 결국 같은 말입니다.

> Allow text to reflow and avoid small fixed-width containers or tight squeezes where possible.

## 높이도 같이 늘어납니다

가로만 문제가 아닙니다. 같은 문서가 라틴 문자가 아닌 글자들에 대해 이렇게 적었습니다.

> non-Latin text to have much taller characters than Latin text. Not only that, but these scripts often require more vertical space between lines

태국어, 데바나가리(힌디어), 아랍어처럼 위아래로 붙는 표시가 있는 글자들이 그렇습니다. 한 줄로 잡아 둔 칸이 그 언어에서만 글자 위아래가 잘립니다.

칸 높이를 글자 크기에 딱 맞춰 잡지 말고 **위아래로 여유를 주세요.** 줄 간격도 한국어에 맞춰 좁혀 두면 그 언어에서 줄끼리 붙습니다.

## 폰트에 없는 글자는 네모가 됩니다

TextMeshPro 는 쓸 글자를 미리 그림으로 구워 둡니다([TextMeshPro 는 글자를 미리 그림으로 구워 둔다](/posts/unity-ui-textmeshpro/)). 그래서 **구울 때 없던 글자는 그릴 수가 없습니다.** 한글 폰트로 구워 둔 에셋에 일본어 한자나 아랍어가 들어오면 그 자리가 비어 버립니다.

빈 자리를 메우는 장치가 폴백입니다. 순서가 정해져 있습니다.

<figure class="diagram">
<svg viewBox="0 0 680 264" role="img" aria-label="글자 하나를 그릴 때 폰트 에셋과 폴백 목록을 차례로 찾는 순서">
<text x="24" y="24" font-size="13" fill="var(--text)">글자 하나를 그릴 때 찾는 순서</text>
<rect x="24" y="56" width="148" height="70" rx="8" fill="var(--accent)" fill-opacity="0.18" stroke="var(--accent)"></rect>
<text x="98" y="88" font-size="11.5" fill="var(--text)" text-anchor="middle">쓰고 있는</text>
<text x="98" y="108" font-size="11.5" fill="var(--text)" text-anchor="middle">폰트 에셋</text>
<line x1="175" y1="91" x2="181" y2="91" stroke="var(--text-muted)"></line>
<path d="M183 91 l-6 -4 l0 8 z" fill="var(--text-muted)"></path>
<rect x="186" y="56" width="148" height="70" rx="8" fill="var(--accent)" fill-opacity="0.18" stroke="var(--accent)"></rect>
<text x="260" y="88" font-size="11.5" fill="var(--text)" text-anchor="middle">그 폰트의</text>
<text x="260" y="108" font-size="11.5" fill="var(--text)" text-anchor="middle">Fallback 목록</text>
<line x1="337" y1="91" x2="343" y2="91" stroke="var(--text-muted)"></line>
<path d="M345 91 l-6 -4 l0 8 z" fill="var(--text-muted)"></path>
<rect x="348" y="56" width="148" height="70" rx="8" fill="var(--accent)" fill-opacity="0.18" stroke="var(--accent)"></rect>
<text x="422" y="88" font-size="11.5" fill="var(--text)" text-anchor="middle">TMP Settings 의</text>
<text x="422" y="108" font-size="11.5" fill="var(--text)" text-anchor="middle">전역 Fallback</text>
<line x1="499" y1="91" x2="505" y2="91" stroke="var(--text-muted)"></line>
<path d="M507 91 l-6 -4 l0 8 z" fill="var(--text-muted)"></path>
<rect x="510" y="56" width="148" height="70" rx="8" fill="var(--warn)" fill-opacity="0.18" stroke="var(--warn)"></rect>
<text x="584" y="88" font-size="11.5" fill="var(--text)" text-anchor="middle">거기에도 없으면</text>
<text x="584" y="108" font-size="11.5" fill="var(--text)" text-anchor="middle">네모가 뜹니다</text>
<text x="24" y="152" font-size="11" fill="var(--text-muted)">왼쪽에 없으면 오른쪽으로 넘어갑니다.</text>
<text x="24" y="180" font-size="12.5" fill="var(--text)">한글 폰트 하나로 시작하면 영어는 나옵니다. 일본어 한자와 아랍어에서 네모가 뜹니다.</text>
<text x="24" y="202" font-size="11.5" fill="var(--text-muted)">폴백을 길게 걸수록 찾는 길도 길어지고, 실행 중에 새로 굽는 글자도 늘어납니다.</text>
<text x="24" y="230" font-size="12.5" fill="var(--text)">언어를 하나 늘리는 일은 문장을 늘리는 일이면서 폰트를 늘리는 일이기도 합니다.</text>
<text x="24" y="254" font-size="11.5" fill="var(--text-muted)">어떤 언어를 낼지는 폰트를 고르기 전에 정해져 있어야 합니다.</text>
</svg>
<figcaption>폰트 에셋 자기 목록을 먼저 보고, 그다음 TMP Settings 의 전역 목록을 봅니다.</figcaption>
</figure>

- 폰트 에셋마다 **자기 Fallback 목록**이 있고, 그것을 먼저 봅니다
- 거기에 없으면 **TMP Settings 의 전역 Fallback 목록**을 봅니다
- 그래도 없으면 네모가 뜹니다. 네모 대신 무엇을 보여줄지는 TMP Settings 에서 바꿀 수 있지만, 안 보이는 것을 다른 안 보이는 것으로 바꾸는 것뿐입니다

여기서 시안 쪽 결정이 하나 생깁니다. **언어마다 다른 폰트를 쓸 것인가, 한 폰트로 갈 것인가.**

- 언어마다 다른 폰트를 쓰면 각 언어가 제 모양으로 나옵니다. 대신 폰트가 그만큼 늘어나고, 언어마다 글자 크기와 줄 간격을 다시 잡아야 합니다
- 한 폰트로 가면 관리가 쉽습니다. 대신 그 폰트가 모든 언어를 커버해야 하고, 커버하는 폰트는 대개 무겁습니다

어느 쪽이든 **어떤 언어를 낼지가 폰트를 고르기 전에 정해져 있어야** 합니다. 나중에 언어를 하나 추가하는 일은 문장을 추가하는 일이 아니라 폰트를 추가하는 일입니다. 굽는 글자가 늘어나면 메모리도 같이 늘어납니다([동적으로 채우는 글자는 본 만큼 램에 쌓인다](/posts/unity-ui-dynamic-font-memory/)).

## 오른쪽에서 왼쪽으로 읽는 언어

아랍어와 히브리어는 오른쪽에서 왼쪽으로 읽습니다. 이 언어를 낼 계획이면 **글자만 뒤집히는 게 아닙니다.**

<x-tabs>
<figure class="diagram" data-tab="왼쪽에서 오른쪽으로 (한국어·영어)">
<svg viewBox="0 0 680 262" role="img" aria-label="왼쪽에서 오른쪽으로 읽는 언어의 화면 배치">
<text x="24" y="26" font-size="13" fill="var(--text)">뒤로 가기는 왼쪽 위, 진행 바는 왼쪽부터 찹니다</text>
<rect x="140" y="40" width="400" height="190" rx="10" fill="var(--bg-subtle)" stroke="var(--border)"></rect>
<path d="M172 58 l-14 8 l14 8 z" fill="var(--accent)"></path>
<text x="180" y="71" font-size="12.5" fill="var(--text)" text-anchor="start">화면 제목</text>
<rect x="158" y="92" width="22" height="22" rx="4" fill="var(--accent2)" fill-opacity="0.35" stroke="var(--accent2)"></rect>
<rect x="188" y="98" width="180" height="10" rx="3" fill="var(--text-muted)" fill-opacity="0.35"></rect>
<rect x="158" y="122" width="22" height="22" rx="4" fill="var(--accent2)" fill-opacity="0.35" stroke="var(--accent2)"></rect>
<rect x="188" y="128" width="180" height="10" rx="3" fill="var(--text-muted)" fill-opacity="0.35"></rect>
<rect x="158" y="152" width="22" height="22" rx="4" fill="var(--accent2)" fill-opacity="0.35" stroke="var(--accent2)"></rect>
<rect x="188" y="158" width="180" height="10" rx="3" fill="var(--text-muted)" fill-opacity="0.35"></rect>
<rect x="158" y="186" width="364" height="9" rx="4" fill="var(--border)"></rect>
<rect x="158" y="186" width="140" height="9" rx="4" fill="var(--accent)"></rect>
<rect x="440" y="204" width="84" height="22" rx="6" fill="var(--accent)" fill-opacity="0.22" stroke="var(--accent)"></rect>
<text x="482" y="219" font-size="10.5" fill="var(--text)" text-anchor="middle">확인</text>
<text x="24" y="252" font-size="11.5" fill="var(--text-muted)">아이콘이 글자 왼쪽에 오고, 확인 버튼이 오른쪽 아래에 옵니다.</text>
</svg>
<figcaption>익숙한 배치입니다.</figcaption>
</figure>
<figure class="diagram" data-tab="오른쪽에서 왼쪽으로 (아랍어·히브리어)">
<svg viewBox="0 0 680 262" role="img" aria-label="오른쪽에서 왼쪽으로 읽는 언어에서 화면 전체가 좌우로 뒤집힌 배치">
<text x="24" y="26" font-size="13" fill="var(--warn)">글자만이 아니라 화면 전체가 좌우로 뒤집힙니다</text>
<rect x="140" y="40" width="400" height="190" rx="10" fill="var(--bg-subtle)" stroke="var(--border)"></rect>
<path d="M508 58 l14 8 l-14 8 z" fill="var(--accent)"></path>
<text x="500" y="71" font-size="12.5" fill="var(--text)" text-anchor="end">화면 제목</text>
<rect x="500" y="92" width="22" height="22" rx="4" fill="var(--accent2)" fill-opacity="0.35" stroke="var(--accent2)"></rect>
<rect x="312" y="98" width="180" height="10" rx="3" fill="var(--text-muted)" fill-opacity="0.35"></rect>
<rect x="500" y="122" width="22" height="22" rx="4" fill="var(--accent2)" fill-opacity="0.35" stroke="var(--accent2)"></rect>
<rect x="312" y="128" width="180" height="10" rx="3" fill="var(--text-muted)" fill-opacity="0.35"></rect>
<rect x="500" y="152" width="22" height="22" rx="4" fill="var(--accent2)" fill-opacity="0.35" stroke="var(--accent2)"></rect>
<rect x="312" y="158" width="180" height="10" rx="3" fill="var(--text-muted)" fill-opacity="0.35"></rect>
<rect x="158" y="186" width="364" height="9" rx="4" fill="var(--border)"></rect>
<rect x="382" y="186" width="140" height="9" rx="4" fill="var(--accent)"></rect>
<rect x="156" y="204" width="84" height="22" rx="6" fill="var(--accent)" fill-opacity="0.22" stroke="var(--accent)"></rect>
<text x="198" y="219" font-size="10.5" fill="var(--text)" text-anchor="middle">확인</text>
<text x="24" y="252" font-size="11.5" fill="var(--text-muted)">뒤로 가기도, 아이콘 자리도, 진행 바가 차는 방향도, 버튼 자리도 반대입니다.</text>
</svg>
<figcaption>한국어 시안을 그대로 쓰면 뒤로 가기 화살표가 앞으로 가는 것처럼 보입니다.</figcaption>
</figure>
</x-tabs>

TextMeshPro 쪽에는 글자를 오른쪽에서 왼쪽으로 흘리는 스위치가 있습니다(인스펙터의 RTL 토글, 코드로는 `isRightToLeftText`). 그런데 그 스위치가 해 주는 것은 **글자 한 덩어리를 뒤집는 것까지**입니다.

나머지는 사람이 뒤집어야 합니다.

- **뒤로 가기 화살표**가 반대를 가리켜야 합니다. 그대로 두면 앞으로 가는 버튼처럼 보입니다
- **아이콘과 글자의 순서**가 바뀝니다. 가로 레이아웃 그룹에는 순서를 뒤집는 체크박스가 있습니다
- **진행 바와 게이지가 차는 방향**이 반대입니다
- **앵커**도 반대쪽 모서리에 붙어야 합니다([앵커는 화면이 늘어날 때 어디에 붙어 있을지 정한다](/posts/unity-ui-rect-transform-anchor/))
- 숫자와 시계 방향처럼 **안 뒤집는 것들**도 있습니다. 이건 규칙이 아니라 그 언어권의 관습이라 확인이 필요합니다

RTL 언어를 낼 거면 **시안을 좌우 반전한 버전으로 한 장 더** 주셔야 합니다. 반전하면 안 되는 요소를 그 시안에 표시해 주시면 더 좋습니다.

## 글자를 그림에 굽지 마세요

로고, 배너, 버튼 배경, 스킬 아이콘 위의 이름. 그림 파일 안에 글자가 들어 있으면 **언어 수만큼 그 그림을 다시 그려야 합니다.**

유니티 쪽에서 언어마다 다른 그림을 넣는 방법은 있습니다. 그래도 문제는 남습니다.

- 그림 장수가 언어 수만큼 늘어납니다. 아틀라스와 메모리도 같이 늘어납니다([버튼 이미지를 통째로 늘리면 모서리가 같이 늘어난다](/posts/unity-ui-image-export/))
- 문구 한 줄을 고칠 때마다 번역이 아니라 **그림 작업**이 돌아옵니다
- 글자 크기를 화면에서 조절할 수 없습니다

그래서 **배경은 그림으로, 글자는 Text 로** 나눠 주시는 게 좋습니다. 로고처럼 그 자체가 상표인 것은 예외입니다. 그건 원래 번역하지 않습니다.

## 문장을 조각으로 이어 붙이지 마세요

`"골드 " + 개수 + "개를 얻었습니다"` 처럼 만들면 한국어에서는 잘 돌아갑니다. 영어로 옮기면 어순이 다릅니다. 언어에 따라 숫자가 문장 맨 앞에 오기도 하고 맨 뒤에 오기도 합니다.

그래서 문장은 **자리를 표시한 한 덩어리**로 넘깁니다.

```
{0} 골드를 얻었습니다
You obtained {0} gold
```

숫자에 따라 말이 바뀌는 것도 있습니다. 영어는 `1 item` 과 `2 items` 로 갈리고, 어떤 언어는 세 가지 이상으로 갈립니다. 유니티 로컬라이제이션 패키지에는 이걸 다루는 장치가 들어 있습니다. 문서 표현으로는 "Use the Smart Strings feature to add logic to automatically replace specific strings, such as placeholders and plurals" 입니다.

시안 쪽에서 해 주실 것은 간단합니다. **숫자나 이름이 들어가는 문장은 잘라서 주지 말고 통째로** 주시고, 어디가 채워지는 자리인지 표시해 주시면 됩니다.

## 붙이는 시점이 늦으면 비쌉니다

유니티에는 로컬라이제이션 패키지가 있습니다. 붙이는 순서는 이렇습니다.

1. `Edit > Project Settings > Localization` 에서 설정을 만듭니다
2. **Locale Generator** 로 낼 언어들을 만듭니다
3. `Window > Asset Management > Localization Tables` 에서 **String Table Collection** 을 만듭니다. Key 하나에 언어별 칸이 생깁니다
4. 화면의 텍스트 컴포넌트를 **우클릭해서 Localize** 를 고르면 연결 컴포넌트가 붙습니다
5. 그림이나 소리처럼 에셋을 바꿔야 하면 **Asset Table Collection** 을 씁니다

문제는 시점입니다. **나중에 붙이면 화면에 박힌 문장을 전부 찾아내는 일부터** 해야 합니다. 프리팹 안에, 코드 안에, 스크립터블 오브젝트 안에 흩어져 있습니다.

그래서 시안을 넘길 때 **"이거 다른 언어로도 나가나요"** 한 줄 물어봐 주시는 게 실제로 큽니다. 나간다는 답이 나오면 칸을 잡는 방식부터 달라집니다.

## 시안을 넘길 때 적어 주면 좋은 것

| 항목 | 적어 줄 것 |
| --- | --- |
| 나갈 언어 | 어떤 언어로 낼 계획인지. 미정이면 미정이라고 |
| 칸 잡는 방식 | 고정인지, 가장 긴 언어 기준인지, 내용만큼 늘어나는지 |
| 넘칠 때 | 잘리는지, 줄어드는지, 두 줄이 되는지 |
| 두 줄 | 두 줄이 되면 옆 요소가 밀려도 되는지, 칸 높이가 커져도 되는지 |
| 높이 여유 | 글자 위아래 여백과 줄 간격을 한국어에 딱 맞춰 둔 것은 아닌지 |
| 그림 속 글자 | 그림 안에 글자가 들어 있는 것이 어디인지 |
| 채워지는 자리 | 숫자나 이름이 들어가는 문장과 그 자리 |
| RTL | 아랍어·히브리어를 낼 거면 좌우 반전 시안과 반전하면 안 되는 요소 |

## 정리

- 번역하면 길어지고, **짧은 문구일수록 배율이 큽니다.** 버튼과 탭 라벨이 가장 위험합니다
- 칸은 한국어에 딱 맞추지 말고, 가장 긴 언어에 맞추거나 내용만큼 늘어나게 잡습니다
- 가로만이 아니라 **높이도** 늘어납니다. 글자 위아래 여백과 줄 간격에 여유를 주세요
- 폰트에 없는 글자는 네모가 됩니다. 폰트 에셋 자기 폴백을 먼저 보고, 그다음 TMP Settings 의 전역 폴백을 봅니다
- 언어를 하나 늘리는 일은 **폰트를 하나 늘리는 일**이기도 합니다. 낼 언어는 폰트를 고르기 전에 정해져 있어야 합니다
- 오른쪽에서 왼쪽으로 읽는 언어에서는 글자만이 아니라 **화면 전체가 뒤집힙니다.** 좌우 반전 시안이 따로 필요합니다
- 그림 안에 글자를 굽지 마세요. 배경은 그림, 글자는 Text 로 나눕니다
- 문장은 조각으로 이어 붙이지 말고 채워지는 자리를 표시한 한 덩어리로 넘깁니다