인사이트//8 최소 읽기 시간

스타트업을 위한 i18n: 언제 국제화해야 하는가 (그리고 리라이트를 피하는 방법)

Eray Gündoğmuş
공유

거의 모든 스타트업에서 Series A 즈음에 이런 대화가 일어납니다. 누군가 analytics를 보다가 가입자의 30%가 영어권이 아닌 국가에서 오고 있다는 사실을 발견합니다. 제품은 영어 전용입니다. 그 코호트의 이탈률은 처참합니다. 엔지니어링 리드가 말합니다. "국제화가 필요합니다."

그러면 견적이 돌아옵니다. 최소 6개월.

그 견적은 거의 항상 정확하고, 거의 항상 피할 수 있습니다.

i18n 레트로핏의 실제 비용

CSA Research에 따르면, 소비자의 87%는 자국어로 된 대안이 존재할 때 영어 전용 제품을 구매하지 않는다고 합니다. 현지화 시장은 2023년 62억 7천만 달러를 기록했으며 계속 성장하고 있습니다. 이는 틈새 수치가 아닙니다 — 여러분이 조용히 codebase에 설치해 버린 addressable market의 상한선입니다.

레트로핏이 비싼 이유는 국제화 자체가 기술적으로 어렵기 때문이 아닙니다. i18n을 고려하지 않고 애플리케이션을 구축하는 방식 때문입니다.

  • 200개 component에 흩어진 string literal
  • 미국 관습으로 하드코딩된 날짜 및 숫자 형식
  • 영어 텍스트 길이에 맞게 설정된 database 컬럼 크기
  • 한 번도 고려되지 않은 오른쪽에서 왼쪽(RTL) 레이아웃
  • 영어 문법 가정에 기반하여 구성된 콘텐츠
  • 단일 지역에 묶인 timezone 처리

이 중 어떤 것이든 처음부터 올바르게 하는 건 저렴합니다. codebase가 4만 줄이 되고 4명의 엔지니어가 각자 기존 가정 위에 쌓아 올린 18개월 후에 해결하려면 고통스럽습니다.

6개월 견적은 번역을 추가하기 위한 것이 아닙니다. i18n을 고려하지 않고 구축된 애플리케이션 부분을 감사하고 다시 작성하기 위한 것입니다. 번역은 작업의 20%에 불과합니다. 나머지 80%는 고고학입니다.

실제로 언제 국제화해야 할까요?

이 질문에는 두 가지 부분이 있습니다. architecture를 i18n 준비 상태로 만드는 시점과 실제로 여러 언어를 출시하는 시점입니다.

Architecture: 첫날부터, 항상.

i18n을 준비하는 상태로 처음부터 구축하는 비용은 약 2시간의 설정입니다. 번역하는 것이 아닙니다. 번역가를 고용하는 것도 아닙니다. 그냥 문을 닫지 않는 결정을 내리는 것입니다.

  • 문자열을 하드코딩하는 대신 resource 파일로 외부화하기
  • locale을 인식하는 날짜/시간 라이브러리 사용 (Luxon, locale 지원이 있는 date-fns, Temporal)
  • Intl.NumberFormat을 래핑하는 숫자 형식 접근 방식 선택
  • UI에 텍스트 확장을 위한 여유 공간 두기 (독일어는 영어보다 30% 길어질 수 있습니다)
  • 처음부터 locale을 사용자 preference로 저장하기

이것은 섣부른 최적화가 아닙니다. 금도금도 아닙니다. 변경하고 싶을 수 있는 config 값에 환경 변수를 사용하는 것과 같은 이유입니다 — 특정 필요를 예측하는 것이 아니라 특정 함정을 피하는 것입니다.

번역 출시: 신호가 생긴 후에.

첫날에 프랑스어를 출시할 필요는 없습니다. 준비가 되어 있어야 합니다. 실제로 두 번째 언어에 투자하는 결정은 데이터에 의해 주도되어야 합니다.

  • 타겟 시장에서 유기적인 가입자가 발생하고 있음
  • 영업 대화에서 거래를 성사시키기 위해 필요함
  • 영어 보급률이 낮은 시장에 진입하고 있음
  • 특정 언어의 고객 코호트가 더 높은 이탈률을 보임

그 신호가 나타날 때, "i18n 준비"는 두 번째 언어를 6개월이 아니라 1주일 안에 출시할 수 있다는 것을 의미합니다.

3개월 타임라인 함정

팀이 빠지는 방식이 있습니다. i18n이 필요하다는 것을 알고, 잘못하고 싶지 않아서 "제대로 된 i18n 프로젝트"를 계획합니다. 3개월로 범위를 정합니다. 그 견적에는 다음이 포함됩니다.

  • 기존 문자열 감사
  • 번역 pipeline 구축
  • translation management system 통합
  • 번역 vendor와의 조율
  • 모든 locale에 걸친 QA

프로젝트가 계획 중인 동안 로드맵은 계속 움직입니다. 3개월 프로젝트는 feature를 출시하지 않기 때문에 계속 우선순위가 낮아집니다. 마침내 우선순위가 높아질 때는 codebase가 성장했기 때문에 5개월 프로젝트가 됩니다.

함정은 i18n을 빅뱅 마이그레이션으로 처리하는 것입니다. 대안은 architecture부터 시작하여 점진적으로 쌓는 기반으로 처리하는 것입니다.

최소 실행 가능한 i18n 설정

시드 단계의 React 또는 Next.js 앱에서 "i18n 준비"가 실제로 어떤 모습인지 살펴보겠습니다. 설정에 2시간이 걸리고 번역을 준비하기 전까지 지속적인 오버헤드가 없습니다.

1단계: 문자열 외부화 방식을 선택합니다.

표시 문자열을 하드코딩하지 마십시오. 최소한 JSON 파일에 넣으십시오. 더 좋은 방법: 처음부터 타입 안전한 솔루션을 사용하십시오.

// 나쁜 예 — 하드코딩된 문자열
<button>Get started for free</button>

// 좋은 예 — 현재 영어만 있어도 외부화됨
// messages/en.json
{
  "cta.getStarted": "Get started for free"
}

// Component
const t = useTranslations();
<button>{t('cta.getStarted')}</button>

아직 translation platform이 필요하지 않습니다. locale당 하나의 JSON 파일, 영어만 있더라도 충분합니다. 인라인 문자열 대신 t()를 사용하는 습관이 중요합니다.

2단계: 처음부터 locale을 인식하는 형식 사용.

// 나쁜 예 — 미국 형식 하드코딩
const formatted = `$${price.toFixed(2)}`;
const date = new Date(ts).toLocaleDateString('en-US');

// 좋은 예 — locale 인식
const formatted = new Intl.NumberFormat(locale, {
  style: 'currency',
  currency: 'USD'
}).format(price);

const date = new Intl.DateTimeFormat(locale, {
  dateStyle: 'medium'
}).format(new Date(ts));

나중에 두 번째 locale을 추가할 때 형식이 그냥 작동합니다. 80개 파일에서 grep-and-replace가 필요 없습니다.

3단계: 텍스트 확장을 고려하여 디자인합니다.

UI에 여유 공간을 두십시오. 텍스트가 길어질 때 우아하게 대응하는 CSS를 사용하십시오. 텍스트 컨테이너에 픽셀 고정 너비를 피하십시오. 이는 디자인에서 아무런 비용이 들지 않지만 독일어를 출시할 때 QA에서 실제 비용을 절약합니다.

4단계: locale을 1등급 사용자 속성으로 저장합니다.

하나의 언어만 출시하더라도 사용자 모델에 preferred_locale을 저장하십시오. 두 번째 언어를 추가할 때 기존 사용자는 이미 locale preference가 저장되어 있습니다. 실시간 데이터로 schema를 마이그레이션할 필요가 없습니다.

스타트업의 흔한 실수

"필요할 때 i18n을 추가하면 됩니다." 필요한 순간이 바로 제대로 할 시간이 없는 순간입니다. 결정을 촉발하는 신호 — 프랑스어를 요구하는 주요 고객, 지역별 go-to-market 추진 — 는 항상 긴급함을 동반합니다.

커스텀 번역 pipeline 구축. Translation management는 이미 해결된 문제입니다. 커스텀 솔루션은 구축하는 데 몇 주, 유지하는 데 몇 달이 걸립니다. 이미 존재하는 툴링을 사용하십시오.

현지화를 단순히 번역으로 처리하기. 언어는 현지화의 20%에 불과합니다. 통화, 날짜 형식, 주소 형식, 법적 요구사항, RTL 지원, locale별 UX 관습 — 이것들이 나머지 80%입니다. 깨진 레이아웃의 번역된 문자열은 여전히 깨진 경험입니다.

번역가에게 JSON 파일에 직접 접근 권한 부여. 사람 번역가는 JSON을 수동으로 편집해서는 안 됩니다. 오류율이 높고 피드백 주기가 느립니다. 번역가에게는 맥락, 글자 수 제한, 용어 일관성 적용이 있는 번역 작업을 위한 UI가 필요합니다.

영어 어순이 일반화된다고 가정하기. JavaScript 문자열 interpolation으로 번역된 문자열을 연결하면 문법 구조가 다른 언어에서 깨집니다. 변수가 있는 모든 것에 ICU message format을 사용하십시오.

// 나쁜 예 — 영어 어순 가정
t('welcome') + ' ' + userName + '!'

// 좋은 예 — ICU 형식, locale이 토큰 순서를 재배열할 수 있음
t('welcome', { name: userName })
// en: "Welcome, {name}!"
// ja: "{name}さん、ようこそ!"

의사결정 프레임워크

현재 위치와 해야 할 일을 결정하는 데 사용하십시오.

단계i18n Architecture활성 번역
제품 개발 전외부화된 문자열, locale 인식 형식 설정아니오
PMF 전기반 유지, 아직 번역하지 않음아니오
PMF 이후, Series A 전국제적 신호가 보인다면 상위 2개 언어 번역아마도
Series A 이후현지화를 제품 요구사항으로 처리

핵심 통찰: architecture 결정과 번역 결정은 독립적입니다. architecture 결정은 지금 내리십시오. 번역 결정은 데이터가 말할 때 내리십시오.

실용적인 체크리스트

다음 component를 작성하기 전에 이것을 확인하십시오.

  • 문자열이 외부화됨 (JSX/템플릿에 하드코딩되지 않음)
  • 날짜 형식이 locale 인식 API 사용
  • 숫자 및 통화 형식이 Intl.NumberFormat 사용
  • 사용자 모델에 locale 필드 있음
  • UI 레이아웃이 30% 더 긴 텍스트로 테스트됨
  • 번역 가능한 부분과 문자열 연결 없음
  • 변수가 있는 문자열에 ICU message format 사용
  • 복수형이 올바르게 처리됨 (단순히 "s" 추가가 아님)

이 모든 항목을 확인하는 데 2시간이 걸립니다. 규모가 커질 때 어느 하나라도 놓치면 몇 주가 걸립니다.

실제로 어떻게 보이는가

실제로 여러 언어를 출시할 준비가 되었을 때 워크플로우는 "고고학적 발굴"에서 "번역 프로젝트"로 바뀝니다. 다음이 필요합니다.

  1. 번역가에게 소스 문자열을 내보내는 방법
  2. 번역을 위한 검토 프로세스
  3. 코드 배포 없이 문자열을 업데이트하는 배포 pipeline
  4. 각 사용자에게 올바른 locale을 런타임에 제공하기

Better i18n에서 우리는 이 특정 문제를 중심으로 플랫폼을 구축했습니다 — React, Next.js, Vue, Svelte를 위한 타입 안전 SDK, 번역이 코드처럼 검토를 거치도록 하는 Git 기반 번역 워크플로우, 그리고 재배포 없이 번역을 업데이트할 수 있는 CDN 제공. 가격 페이지의 무료 플랜은 예산 없이 기반을 구축하려는 초기 단계 팀을 위한 규모입니다. 기술적인 부분이 어떻게 맞춰지는지 보고 싶다면 개발자 페이지에 전체 그림이 있습니다.

6개월 리라이트는 불가피한 것이 아닙니다. 너무 오래 미룬 2시간짜리 결정의 결과입니다.

Comments

Loading comments...