Unity Localization 패키지 완벽 가이드: Smart Strings와 동적 텍스트 바인딩 실전 활용법

Unity Localization 패키지에서 Smart Strings 문법과 동적 변수 바인딩을 활용해 다국어 복수형 처리, UI 자동 갱신, 성능 최적화(GC Alloc 방지)를 구현하는 방법을 정리합니다.

✓ 복사 완료!
챕터가격 정책 & 현지화
난이도중급
상태● 검토 완료
대상 엔진
Unity
최종 업데이트
Unity Localization 패키지 완벽 가이드: Smart Strings와 동적 텍스트 바인딩 실전 활용법

핵심 요약

Unity 공식 Localization 패키지(com.unity.localization 1.0+)의 Smart Strings는 다국어 번역 시 동적 매개변수 치환, 복수형(Pluralization), 성별/조건부 분기(Choose)를 C# 하드코딩 없이 테이블 데이터 레벨에서 처리할 수 있는 강력한 포맷팅 시스템입니다. LocalizedString 인스턴스의 Arguments 목록에 데이터를 전달하고 LocalizeStringEvent 또는 StringChanged 콜백을 구독하면 언어 변경 및 런타임 데이터 갱신 시 UI가 자동으로 리빌드됩니다.


왜 단순 string.Format 대신 Smart Strings를 써야 할까?

게임 클라이언트에서 다국어를 지원할 때 가장 흔히 겪는 문제는 언어마다 문장 구조, 어순, 복수형 규칙이 완전히 다르다는 점입니다.

예를 들어 "{0}이(가) {1}골드를 획득했습니다."라는 문장을 C#의 string.Format()이나 보간 문자열($"{user} earned {gold}")로 처리하면 다음과 같은 한계에 부딪힙니다.

  1. 어순 불일치: 일부 언어는 주어, 목적어, 동사의 위치가 바뀌어 인덱스 순서({0}, {1})를 번역가가 직관적으로 파악하기 어렵습니다.
  2. 복수형(Pluralization) 차이: 영어는 1개(1 coin)와 다수(2 coins)만 구분하지만 러시아어나 아랍어는 3~6가지 복수형 규칙을 가집니다. 이를 C# if문으로 분기하면 코드베이스가 특정 언어 로직에 종속됩니다.
  3. 성별 및 조건 분기: 캐릭터 성별이나 특정 상태에 따라 달라지는 호칭을 C# 코드에서 일일이 분기해야 합니다.
비교 항목C# string.FormatUnity Smart Strings
매개변수 참조 방식숫자 인덱스 ({0}, {1})명명된 키/프로퍼티 ({player.name}, {count})
복수형 처리C# 스크립트에서 직접 if/switch 구현 필요{count:plural:{} item|{} items} 테이블 자체 처리
조건부 분기코드에서 문자열 조합 필요{gender:choose(Male|Female):그|그녀} 내장 문법 지원
데이터 바인딩수동 포맷 호출 후 UI 텍스트 대입LocalizedString 이벤트 기반 자동 UI 갱신

Unity Localization 환경 설정 및 Smart String 활성화

Smart Strings를 프로젝트에 도입하는 절차는 다음 3단계로 구성됩니다.

1단계: Localization 패키지 설치

Window > Package Manager에서 Localization 패키지를 설치합니다.

2단계: Localization Settings 및 Locale 구성

  1. Project Settings > Localization으로 이동하여 Create Localization Settings를 클릭합니다.
  2. 지원할 언어(예: Korean (ko), English (en), Japanese (ja))를 추가하고 Default Locale을 설정합니다.

3단계: String Table 생성 및 Smart String 활성화

  1. Window > Asset Management > Localization Tables 창을 엽니다.
  2. New Table Collection에서 String Table Collection을 생성합니다.
  3. 생성된 테이블에서 특정 키를 추가한 뒤 열 설정에서 Smart 체크박스를 반드시 활성화해야 합니다. 이 체크박스가 꺼져 있으면 중괄호({})가 단순 리터럴로 취급됩니다.

Unity Localization Table에서 Smart String 옵션을 활성화하는 화면


Smart Strings 핵심 문법과 다국어 처리 패턴

Unity Smart Strings는 오픈소스 포맷터 라이브러리인 SmartFormat을 기반으로 동작합니다. 자주 쓰이는 대표 패턴을 살펴봅니다.

1. 명명된 변수 치환 (Named Placeholders)

객체의 프로퍼티나 딕셔너리 키를 직접 지정할 수 있습니다.

// 테이블 엔트리
환영합니다, {player.Name}님! 현재 레벨은 {player.Level}입니다.

2. 복수형 처리 (Plural Form)

언어별 규칙에 맞게 숫자에 따른 단어 형태를 분기합니다. plural 포맷터를 사용하며 {}를 사용해 현재 전달된 숫자 값을 재참조할 수 있습니다.

// 영어 (en)
You defeated {count:plural:{} enemy|{} enemies}!

// 한국어 (ko)
적 {count}마리를 처치했습니다!

3. 조건부 분기 (Choose Formatter)

열거형(Enum)이나 문자열 값에 따라 다른 문장을 출력합니다.

// 성별에 따른 대사 분기
{gender:choose(Male|Female):용사님이 칼을 뽑았습니다.|여전사님이 칼을 뽑았습니다.}

C# 스크립트와 UI 컴포넌트에서의 동적 텍스트 바인딩 구현

Smart String을 실제 런타임 게임 데이터와 연결하는 데이터 파이프라인 흐름은 다음과 같습니다.

flowchart LR
    A[게임 데이터 변경 C# State] --> B[LocalizedString Arguments 갱신]
    B --> C[Smart Format 파싱 엔진]
    C --> D[현재 선택된 Locale 테이블 참조]
    D --> E[LocalizeStringEvent 이벤트 발생]
    E --> F[TextMeshPro / UI Text 갱신]

방법 1: C# 스크립트에서 LocalizedString 직접 제어하기

스크립트에서 LocalizedString을 선언하고 인자를 넘겨 비동기 또는 이벤트 방식으로 텍스트를 가져옵니다.

using System;
using TMPro;
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Tables;

public class QuestUI : MonoBehaviour
{
    [SerializeField] private TMP_Text questText;
    
    [Tooltip("Table: UI_Quests, Entry: KillMonsters_Smart")]
    [SerializeField] private LocalizedString questLocalizedString;

    private int _currentKillCount;
    private int _targetKillCount = 10;
    private string _monsterName = "슬라임";

    private void OnEnable()
    {
        // 언어 변경 및 인자 갱신 시 자동 호출되는 이벤트 구독
        questLocalizedString.StringChanged += OnQuestStringChanged;
        UpdateQuestData(0);
    }

    private void OnDisable()
    {
        questLocalizedString.StringChanged -= OnQuestStringChanged;
    }

    public void UpdateQuestData(int currentKill)
    {
        _currentKillCount = currentKill;

        // Smart String에 바인딩할 Arguments 배열 갱신
        questLocalizedString.Arguments = new object[]
        {
            new { MonsterName = _monsterName, Current = _currentKillCount, Target = _targetKillCount }
        };

        // 변경 사항 반영을 위한 문자열 재평가 요청
        questLocalizedString.RefreshString();
    }

    private void OnQuestStringChanged(string value)
    {
        questText.text = value;
    }
}

방법 2: Localize String Event 컴포넌트 활용 (No-Code/Inspector)

Inspector 중심 워크플로를 원할 경우 UI GameObject에 Localize String Event 컴포넌트를 추가합니다.

  1. Target String을 지정하고 Update String 이벤트에 TextMeshProUGUI.text를 바인딩합니다.
  2. 스크립트에서는 LocalizeStringEvent.StringReference.Arguments만 업데이트하면 에디터와 런타임 양쪽에서 즉각 반영됩니다.

Inspector에서 Localize String Event를 TextMeshPro에 연결한 화면


커스텀 포맷터(Custom Formatter) 확장하기

게임 고유의 서식(예: 재화 단위 축약 K/M/B, 아이템 등급 색상 태그 자동 주입)이 필요하다면 Unity SmartFormat 엔진에 커스텀 포맷터를 등록할 수 있습니다.

using System;
using UnityEngine.Localization.SmartFormat.Core.Extensions;
using UnityEngine.Localization.SmartFormat.Core.Parsing;

public class CurrencyFormatter : IFormatter
{
    public string Name => "currency";

    public bool TryEvaluateFormat(IFormattingInfo formattingInfo)
    {
        if (formattingInfo.CurrentValue is long or int or double)
        {
            double value = Convert.ToDouble(formattingInfo.CurrentValue);
            string formatted = value switch
            {
                >= 1_000_000_000 => $"{value / 1_000_000_000.0:F1}B",
                >= 1_000_000 => $"{value / 1_000_000.0:F1}M",
                >= 1_000 => $"{value / 1_000.0:F1}K",
                _ => value.ToString("N0")
            };

            formattingInfo.Write(formatted);
            return true;
        }

        return false;
    }
}

이 포맷터를 등록하면 테이블에서 {gold:currency} 형태로 즉시 사용할 수 있습니다.


메모리 관리 및 GC Allocation 최적화 가이드

Smart Strings는 문자열 파싱과 리플렉션/박싱(Boxing) 과정을 수반하므로 Update 루프나 잦은 이벤트에서 무분별하게 사용할 경우 GC Allocation 스파이크가 발생할 수 있습니다.

  1. Arguments 배열 캐싱: 매번 new object[]를 생성하지 말고 재사용 가능한 전용 파라미터 컨테이너 클래스나 캐싱된 배열을 사용합니다.
  2. 값 변경 시에만 RefreshString() 호출: 매 프레임 Arguments를 대입하지 않고 데이터의 실질적인 변경(Dirty Flag)이 일어났을 때만 호출합니다.
  3. Global Variables Group 활용: 플레이어 닉네임이나 전역 골드처럼 게임 전반에 쓰이는 값은 LocalizationSettings.StringDatabase.SmartFormatter의 Global Variables에 등록해 중복 바인딩을 제거합니다.

자주 묻는 질문 (FAQ)

Q1. Smart String에서 런타임에 바인딩된 인자 값이 바뀌었는데 UI 텍스트가 갱신되지 않습니다.

LocalizedString.Arguments의 내부 프로퍼티 값을 변경한 경우, 내부적으로 변경 감지 이벤트가 발생하지 않을 수 있습니다. 인자 값을 수정한 직후 반드시 localizedString.RefreshString()을 호출해야 새 인자 값으로 문자열 파싱이 다시 실행됩니다.

Q2. 텍스트에 Rich Text 태그(<color=#FF0000>...</color>)를 포함할 때 중괄호({})와 충돌이 나지 않나요?

HTML 형태의 <> 태그는 Smart Strings 문법과 충돌하지 않습니다. 다만 텍스트 본문에 실제 중괄호 리터럴({, })을 그대로 출력하고 싶다면 \{ 및 \}처럼 역슬래시로 이스케이프해야 파서 에러를 방지할 수 있습니다.

Q3. 언어별로 복수형 규칙(Plural Rules) 구조가 다른데 하나의 테이블 엔트리로 대응이 가능한가요?

가능합니다. Unity SmartFormat은 현재 활성화된 Locale의 문화권(Culture) 정보를 기반으로 동작하므로 영어 엔트리에는 one|other를 적고 러시아어 엔트리에는 one|few|many|other 규칙을 각 언어 테이블 열에 맞게 작성해 두면 활성 언어에 맞춰 올바른 분기가 자동 선택됩니다.


요약

Unity Localization의 Smart Strings는 하드코딩된 C# 문자열 조작을 제거하고 기획/번역 워크플로의 자유도를 극대화하는 표준 도구입니다. UI 텍스트 컴포넌트와 LocalizedString을 느슨하게 결합하고 Dirty 상태 기반 갱신과 커스텀 포맷터를 적절히 병용하여 확장성 높은 다국어 클라이언트를 구축할 수 있습니다.