#5
어떤 앱에서 영어로 다음과 같은 알림 메시지를 본다.
Updated 5 minutes ago.
그런데 동일한 앱의 한국어 화면에서는 이렇게 알람 메시지가 뜬다.
업데이트됨 5분 전
번역가의 실수일까? 99%의 확률로 번역가에게 다음과 같은 2개(혹은 3개)의 문장이 주어졌을 것이다.
Updated
{number} minutes ago
번역가는 서로 다른 문자열인 Updated를 “업데이트됨”으로, {number} minutes ago를 “{number}분 전”으로 옮겼을 것이다.
번역은 틀리지 않았다. 문제는 이 문자열들이 다른 언어를 받아들일 준비가 되어 있지 않았다는 것. 이처럼 번역만으로는 해결할 수 없는 문제를 예방하기 위해 필요한 과정이 인터내셔널라이제이션(Internationalization)이다. 흔히 사용하는 약어인 i18n은 단어의 첫 글자 i와 마지막 글자 n 사이에 18개의 글자가 있다는 데서 나왔다.
*
좋은 로컬라이제이션은 번역 전에 시작된다
인터내셔널라이제이션은 제품을 특정 언어나 문화의 구조에 종속되지 않도록 설계하는 과정이다. 쉽게 말하면, 번역을 시작하기 전에 제품이 여러 언어와 지역을 받아들일 수 있는 조건을 만드는 일이다.
서두의 예시보다도 더 흔히 볼 수 있는 예시로, 미국에서는 날짜를 8/30/2026으로 표시하지만 한국에서는 보통 2026. 8. 30.처럼 표시한다. 미국의 1,234.56과 일부 유럽 국가의 1.234,56은 같은 숫자를 나타내며, 통화 기호의 위치도 지역마다 다르다. 이런 형식을 화면에 직접 입력해 두면 번역가가 텍스트를 아무리 잘 옮겨도 현지 사용자에게 자연스러운 제품을 만들 수 없다.
문장의 길이도 달라진다. 영어의 짧은 버튼 하나가 독일어나 프랑스어에서는 훨씬 길어질 수 있고, 영어를 기준으로 고정된 버튼은 번역문을 전부 표시하지 못한다. 아랍어처럼 오른쪽에서 왼쪽으로 쓰는 언어는 화면의 방향 자체가 달라져야 한다. 사용하려는 글꼴에 한글이나 태국어 문자가 포함되어 있지 않아 글자가 네모로 표시되기도 한다.
이런 문제들은 겉으로는 제각각이지만 공통점이 있다. 번역의 문제가 아니라 제품 구조의 문제라는 점이다.
단어를 이어 붙이면 문장이 될까
소프트웨어 로컬라이제이션에서 특히 자주 만나는 문제 중 하나가 문자열 연결(string concatenation), 즉 여러 개의 짧은 문자열과 데이터를 코드에서 이어 붙여 하나의 문장을 만드는 방식이다.
영어로 다음과 같은 메시지를 만든다고 해보자.
"You have " + count + " new messages."
count가 5라면 화면에는 다음과 같이 표시된다.
You have 5 new messages.
영어에서는 아무 문제가 없어 보인다. 개발자 입장에서도 숫자만 바꾸면 되므로 간단하고 효율적인 구조처럼 느껴진다.
하지만 번역가에게는 문장 전체가 아니라 다음과 같은 조각만 전달될 수 있다.
You have
new messages.
한국어로는 “새 메시지가 5개 있습니다”처럼 숫자와 명사의 위치를 바꾸는 것이 자연스럽다. 그러나 문장이 코드에서 영어 순서로 조립된다면 번역가는 그 순서를 바꿀 수 없다. 각 조각을 정확하게 번역해도 완성된 문장은 어색해진다.
언어에 따라 문제는 더 복잡해진다. 영어는 수량에 따라 message와 messages를 구분하고, 다른 언어는 숫자에 따라 명사의 형태가 두세 가지 이상으로 달라지기도 한다. 성별이나 격에 따라 단어의 형태가 변하는 언어도 있다. 영어 문장 하나를 기준으로 고정한 구조가 모든 언어에서 그대로 작동할 것이라고 기대하기 어려운 이유다. 문장은 레고 블록처럼 단어를 같은 순서로 조립한다고 해서 완성되지 않는다. 언어마다 어순과 문법, 단어 사이의 관계가 다르기 때문이다.
문자열 연결은 왜 이렇게 자주 사용될까
그렇다고 문자열 연결이 단순한 실수라거나 무조건 부정적인 효과만 가져오는 것은 물론 아니다. 개발자는 같은 문구를 여러 번 작성하는 대신 작은 요소로 나누어 재사용하려 한다. 화면의 여러 메시지를 하나의 공통 컴포넌트로 만들고, 바뀌는 부분만 코드에서 삽입하면 개발과 유지 관리가 쉬워 보인다. 뿐만 아니라 번역할 문자열의 수를 줄이면 번역 비용도 절약할 수 있다.
무엇보다 제품이 영어로 먼저 개발되면 이 구조의 문제가 잘 드러나지 않는다. 영어 단어를 영어 어순으로 조립한 결과는 당연히 자연스럽다. 실제 번역을 넣거나 다른 언어로 테스트한 뒤에야 문제가 보인다.
실제 소프트웨어 스트링을 보다 보면 다음과 같은 스트링들을 어렵지 않게 만날 수 있다.
"Delete " + itemName
"Updated " + number + " minutes ago"
userName + " shared " + fileName + " with you"
영어에서는 모두 자연스럽다. 그러나 다른 언어에서는 목적어가 동사보다 앞에 와야 하거나, 숫자에 따라 시간 단위가 달라지거나, 사용자 이름과 파일 이름에 조사나 격변화가 필요할 수 있다.
개별 문자열만 번역하는 사람은 최종 문장이 어떻게 조립되는지 알기 쉽지 않은 경우가 많다. 번역가는 추측해서 작업하고, 문제는 제품 테스트 단계에서야 발견된다. 그때는 번역을 고치는 것만으로 해결할 수 없어 개발팀에 코드 수정을 요청해야 한다.
플레이스홀더는 해결책이자 또 다른 문제
문장 전체를 하나의 문자열로 제공하고, 변하는 정보만 플레이스홀더나 변수로 삽입하면 문자열 연결의 상당 부분을 피할 수 있다.
You have {count} new messages.
번역가는 이제 문장 전체를 보고 순서를 바꿀 수 있다.
새 메시지가 {count}개 있습니다.
플레이스홀더 자체는 문제가 아니다. 사용자 이름, 날짜, 수량처럼 실행할 때마다 달라지는 정보를 문장에 넣기 위해 반드시 필요한 기능이다. 문제는 플레이스홀더를 지나치게 많이 사용하거나, 변수 안에 문법적 의미를 가진 문장 조각까지 넣을 때 발생한다.
예를 들어 다음과 같은 극단적인 케이스를 생각해 볼 수 있다.
{user} {action} {count} {item}.
영문이라면 실제 화면에는 다음과 같이 나타날 수 있다.
Alex deleted 3 files.
하지만 번역가는 {action}에 deleted가 들어가는지, {item}이 files인지 알 수 없다. 설령 알고 있더라도 한국어에서는 “Alex님이 파일 3개를 삭제했습니다”처럼 어순과 조사까지 바꾸어야 한다. {action}과 {item}에 이미 번역된 문장 조각이 들어온다면 번역가가 전체 문법을 조정할 방법이 없다. 이것은 겉으로는 플레이스홀더를 사용했지만, 실제로는 문자열 연결과 같은 문제를 가진다. 코드 밖에서 문장을 이어 붙일 뿐이다.
다음과 같은 문자열도 흔히 볼 수 있다.
Your {0} has been {1} by {2}.
{0}, {1}, {2}가 무엇을 의미하는지 설명이 없다면 번역가는 완성된 문장을 상상해야 한다. 첫 번째 변수는 주문일 수도 있고 계정일 수도 있다. 두 번째에는 approved, rejected, deleted처럼 문법적 형태가 서로 다른 단어가 들어갈 수 있다. 세 번째가 사람인지 시스템인지 날짜인지도 알 수 없다.
변수가 많아질수록 하나의 번역으로 처리할 수 있는 경우의 수는 줄어든다. 기술적으로는 모든 조합이 가능해도, 언어적으로 모든 조합이 자연스러운 것은 아니다.
문자열과 변수를 안전하게 설계하려면
가장 기본적인 원칙은 사용자에게 하나의 메시지로 보이는 문장은 가능한 한 완전한 문장으로 번역하도록 제공하는 것이다.
나쁜 예
"Upload " + fileName + " complete"
나은 예
Upload of {fileName} is complete.
변수에는 사용자 이름, 파일명, 날짜, 숫자처럼 실제로 바뀌어야 하는 데이터만 넣는 것이 좋다. 동사, 전치사, 조사, 문장 종결 표현처럼 언어의 문법을 결정하는 요소를 변수로 만들면 번역 가능한 범위가 급격히 줄어든다.
변수의 이름도 중요하다.
이해하기 어려운 예
Your {0} was updated on {1}.
이해하기 쉬운 예
Your {accountName} was updated on {updateDate}.
여기에 각 변수의 실제 예시와 문장이 표시되는 화면에 대한 설명을 제공하면 번역가가 훨씬 정확하게 판단할 수 있다. 이상적인 상황이라면 스크린샷이나 디자인 링크도 함께 제공하는 것이 가장 좋다.
수량이나 성별에 따라 문장이 달라지는 경우에는 단순한 변수 대신 복수형과 문법적 조건을 처리할 수 있는 메시지 포맷을 사용해야 한다. 대표적으로 ICU MessageFormat은 숫자에 따라 서로 다른 문장을 선택하거나 언어별 어순을 조정할 수 있도록 지원한다. 영어에서는 다음 두 문장이 필요하다.
You have 1 new message.
You have 5 new messages.
한국어에서는 두 경우 모두 다음 구조를 사용할 수 있다.
새 메시지가 1개 있습니다.
새 메시지가 5개 있습니다.
중요한 것은 모든 언어에 영어와 같은 복수형 규칙을 강요하지 않는 것이다. 각 언어가 자체 문법에 따라 필요한 형태를 선택할 수 있어야 한다. 서로 다른 상황에서 우연히 영어 문구가 같다는 이유로 하나의 문자열을 재사용하는 것도 주의해야 한다. 영어의 Open은 파일을 여는 동사일 수도 있고 영업 중이라는 상태를 나타내는 형용사일 수도 있다. 영어에서는 같지만 다른 언어에서는 전혀 다른 단어가 필요할 수 있다. 의미와 맥락이 다르다면 별도의 문자열로 관리하는 편이 안전하다.
번역 전에 문제를 발견하는 방법
인터내셔널라이제이션 문제를 출시 직전에 발견하면 작은 문구 하나를 고치기 위해 코드와 디자인, 번역, 테스트를 다시 거쳐야 할 수 있다. 따라서 실제 번역이 시작되기 전에 문제를 발견하는 과정이 필요하다.
의사 현지화(pseudo-localization)는 원문을 인위적으로 길게 만들거나 특수문자를 넣어 화면에 표시하는 테스트 방식이다. 이를 통해 글자가 잘리는 버튼, 번역되지 않은 하드코딩 문자열, 지원되지 않는 문자, 잘못된 화면 정렬을 조기에 발견할 수 있다.
개발 단계에서 현지화 문자열 앞뒤에 다른 문자열을 직접 연결하는 코드를 탐지하거나, 지나치게 많은 변수가 포함된 문자열을 검토하는 규칙을 마련할 수도 있다. 로컬라이제이션팀이 디자인과 기능 기획 단계부터 참여하면 출시 직전에 발견되는 문제를 더욱 줄일 수 있다. 물론 모든 문장을 언어별로 따로 개발할 수는 없다. 목적은 변수를 없애거나 문자열을 무조건 늘리는 것이 아니라, 코드의 재사용성과 언어의 유연성 사이에서 균형을 찾는 것이다.
잘된 인터내셔널라이제이션은 눈에 띄지 않는다
인터내셔널라이제이션은 번역가나 로컬라이제이션팀만의 책임이 아니다. 개발자는 문자열과 데이터 구조를 설계하고, 디자이너는 번역문이 길어질 가능성을 고려하며, 콘텐츠 작성자는 여러 문화에서 이해할 수 있는 원문을 작성해야 한다. 로컬라이제이션팀은 각 언어에서 발생할 수 있는 문제를 미리 발견하고 이를 제품 요구사항으로 바꾸는 역할을 한다.
제대로 되지 않았을 때는 누구나 문제를 알아차린다. 글자가 잘리고, 날짜가 낯설며, 문장은 기계적으로 조립된 것처럼 보인다. 반대로 잘 되어 있을 때는 사용자가 그 존재를 의식하지 않는다. 제품이 처음부터 자신의 언어로 만들어진 것처럼 자연스럽게 느껴질 뿐이다.
로컬라이제이션은 완성된 제품에 번역을 덧붙이는 마지막 단계가 아니다. 좋은 로컬라이제이션은 첫 문장이 번역되기 훨씬 전, 제품이 다른 언어를 받아들일 수 있는 구조를 만드는 순간부터 시작된다.
*
다음 이야기
→ [로컬라이제이션의 세계] #6 언어 자산(Linguistic Assets)에 대하여
'Localization > Articles' 카테고리의 다른 글
| [로컬라이제이션의 세계] #4 로컬라이제이션 업계의 플레이어들 - 클라이언트 사이드(Client Side) (0) | 2026.08.30 |
|---|---|
| [로컬라이제이션의 세계] #3 로컬라이제이션 업계의 플레이어들 - 벤더 사이드(Vendor Side) (0) | 2026.08.17 |
| [로컬라이제이션의 세계] #2 번역과 로컬라이제이션, 뭐가 다를까 (0) | 2026.08.08 |
| [로컬라이제이션의 세계] #1 시리즈를 시작하며 (0) | 2026.08.07 |
| 번역 시시콜콜 (0) | 2017.10.12 |
