도움 센터

Lingui.js 현지화: PO 파일, React i18n 및 자동화

Lingui.js는 JavaScript 및 React 애플리케이션을 위한 가볍지만 강력한 국제화(i18n) 프레임워크입니다. 번역 카탈로그를 위해 업계 표준인 PO(Portable Object) 파일을 사용하며, 깔끔한 개발자 경험을 위한 강력한 컴파일 타임 매크로를 제공하고, 2kB 미만의 최적화된 번들을 생성합니다. 이 가이드에서는 프로젝트 설정부터 PO 파일 워크플로우, 복수형 처리, l10n.dev를 이용한 번역 자동화까지 모든 것을 다룹니다.

왜 i18n에 Lingui.js를 사용해야 할까요?

Lingui.js는 개발자 경험, 성능 및 전문적인 번역 워크플로우의 결합으로 JavaScript i18n 라이브러리 중에서 두각을 나타냅니다:

  • 깔끔하고 읽기 쉬운 코드: JSX 매크로를 사용하여 자연스럽게 번역을 작성하세요. 라이브러리가 내부적으로 이를 ICU MessageFormat으로 컴파일합니다.
  • 범용성: @lingui/core는 모든 JavaScript 프로젝트에서 작동하며, @lingui/react는 React Server Components(RSC) 지원을 포함한 React 전용 컴포넌트를 추가합니다.
  • 완벽한 리치 텍스트 지원: 번역 가능한 메시지 내에서 React 컴포넌트를 원활하게 사용하세요. 링크, 굵은 텍스트, 아이콘 및 모든 JSX가 완벽하게 지원됩니다.
  • PO 파일 형식: 거의 모든 번역 도구, TMS 및 전문 번역가 워크플로우에서 지원하는 업계 표준 PO 형식을 사용합니다.
  • 가볍고 최적화됨: 코어 라이브러리는 gzipped 기준 2kB 미만이며, React 컴포넌트는 1.3kB만 추가됩니다. 불필요한 데이터는 컴파일 시점에 제거됩니다.
  • AI 번역 준비 완료: Lingui의 메시지 설명과 컨텍스트 주석은 AI 번역기가 정확하고 맥락을 파악한 번역을 생성하는 데 필요한 정보를 제공합니다.

설치

Lingui의 코어 패키지와 개발 도구를 설치하세요. 런타임 패키지(@lingui/core 및 @lingui/react)는 프로덕션 환경에서 필요하며, CLI, Vite 플러그인 및 Babel 매크로는 개발 전용입니다:

npm install @lingui/core @lingui/react
npm install --save-dev @lingui/cli @lingui/vite-plugin @lingui/babel-plugin-lingui-macro

구성

Lingui는 두 개의 구성 파일이 필요합니다: Lingui 구성(로케일 및 카탈로그 경로 정의)과 빌드 도구 구성(컴파일 타임 매크로 활성화).

Lingui 구성

프로젝트 루트에 lingui.config.js 파일을 생성하세요. 여기에서 소스 로케일, 대상 로케일, PO 카탈로그 저장 위치 및 카탈로그 형식을 정의합니다. PO 형식이 기본값이자 권장되는 선택입니다:

// lingui.config.js
import { defineConfig } from "@lingui/cli";
import { formatter } from "@lingui/format-po";

export default defineConfig({
  sourceLocale: "en",
  locales: ["en", "fr", "de", "ja", "es", "zh-CN"],
  catalogs: [
    {
      path: "<rootDir>/src/locales/{locale}/messages",
      include: ["src"],
    },
  ],
  format: formatter({ lineNumbers: false }),
});

Vite 구성

Vite를 사용하는 경우, Babel 매크로와 함께 Lingui 플러그인을 React 플러그인 옆에 추가하세요. 이를 통해 컴파일 타임 메시지 변환과 즉석 카탈로그 컴파일이 가능해집니다:

// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { lingui } from "@lingui/vite-plugin";

export default defineConfig({
  plugins: [
    react({
      babel: {
        plugins: ["@lingui/babel-plugin-lingui-macro"],
      },
    }),
    lingui(),
  ],
});

PO 파일 형식

PO(Portable Object)는 GNU gettext 시스템에서 유래한 업계 표준 번역 파일 형식입니다. Lingui는 전 세계의 번역 도구, TMS 플랫폼 및 전문 번역가들이 널리 지원하기 때문에 기본 카탈로그 형식으로 PO를 사용합니다.

  • 가독성: 대규모 번역 파일도 명확한 msgid/msgstr 쌍으로 사람이 읽기 쉽게 유지됩니다.
  • 번역가 주석: #. 주석을 지원하여 컨텍스트 설명을 번역가에게 직접 전달합니다.
  • 소스 참조: 각 메시지에는 코드베이스의 정확히 어느 위치에서 사용되는지 보여주는 #: file:line 주석이 포함됩니다.
  • 컨텍스트 지원: msgctxt를 사용하여 서로 다른 맥락에서 다른 의미를 갖는 동일한 문자열을 구분하세요.
  • 범용 도구 지원: 거의 모든 번역 관리 시스템(TMS), CAT 도구 및 현지화 플랫폼과 호환됩니다.

추출된 PO 파일 (소스 메시지)

#: src/components/WelcomeBanner.js:6
msgid "Welcome to our platform"
msgstr ""

#: src/components/WelcomeBanner.js:8
msgid "Hello {userName}, check out your <0>dashboard</0> to get started."
msgstr ""

#: src/components/CartSummary.js:5
msgid "{itemCount, plural, =0 {Your cart is empty} one {You have # item in your cart} other {You have # items in your cart}}"
msgstr ""

번역된 PO 파일 (프랑스어)

번역 후 각 msgstr은 현지화된 버전으로 채워집니다. Lingui는 모든 번역에서 ICU MessageFormat 구문, React 컴포넌트를 위한 인덱스 태그, 플레이스홀더 변수를 보존합니다.

#: src/components/WelcomeBanner.js:6
msgid "Welcome to our platform"
msgstr "Bienvenue sur notre plateforme"

#: src/components/WelcomeBanner.js:8
msgid "Hello {userName}, check out your <0>dashboard</0> to get started."
msgstr "Bonjour {userName}, consultez votre <0>tableau de bord</0> pour commencer."

#: src/components/CartSummary.js:5
msgid "{itemCount, plural, =0 {Your cart is empty} one {You have # item in your cart} other {You have # items in your cart}}"
msgstr "{itemCount, plural, =0 {Votre panier est vide} one {Vous avez # article dans votre panier} other {Vous avez # articles dans votre panier}}"

프로젝트 구조

PO 카탈로그를 로케일별로 하위 폴더를 만들어 locales 디렉토리 안에 구성하세요. Lingui CLI는 추출 중에 이러한 파일을 자동으로 생성하고 업데이트합니다. 컴파일된 JS 모듈은 빌드 시점에 생성되므로 수동으로 편집해서는 안 됩니다.

src/
├── locales/
│   ├── en/
│   │   └── messages.po       ← Source (English)
│   ├── fr/
│   │   └── messages.po       ← French
│   ├── de/
│   │   └── messages.po       ← German
│   ├── ja/
│   │   └── messages.po       ← Japanese
│   ├── es/
│   │   └── messages.po       ← Spanish
│   └── zh-CN/
│       └── messages.po       ← Chinese Simplified
├── components/
├── i18n.ts
├── App.tsx
└── ...

React 컴포넌트 번역

Lingui는 메시지를 표시하기 위한 두 가지 주요 접근 방식을 제공합니다: 컴포넌트 콘텐츠를 위한 JSX 매크로와 명령형 문자열을 위한 useLingui 훅입니다. 둘 다 최적화된 출력을 생성하는 컴파일 타임 매크로입니다.

Trans 매크로

번역이 필요한 JSX 콘텐츠를 Trans 매크로로 감싸세요. 변수, HTML 요소 및 React 컴포넌트가 완벽하게 지원되며, 매크로가 이를 인덱스 태그가 포함된 ICU MessageFormat으로 자동으로 변환합니다.

import { Trans } from "@lingui/react/macro";

function WelcomeBanner({ userName }) {
  return (
    <div>
      <h1>
        <Trans>Welcome to our platform</Trans>
      </h1>
      <p>
        <Trans>
          Hello {userName}, check out your <a href="/dashboard">dashboard</a> to
          get started.
        </Trans>
      </p>
    </div>
  );
}

useLingui 훅

JSX 외부의 문자열(알림 메시지, aria 레이블, 속성 값 또는 기타 명령형 코드)에는 태그가 지정된 템플릿 리터럴과 함께 useLingui 매크로 훅을 사용하세요:

import { useLingui } from "@lingui/react/macro";

function NotificationButton() {
  const { t } = useLingui();

  const showAlert = () => {
    alert(t`Your changes have been saved.`);
  };

  return (
    <button onClick={showAlert} aria-label={t`Save changes`}>
      <Trans>Save</Trans>
    </button>
  );
}

메시지 ID 및 설명

Lingui는 메시지 식별을 위한 두 가지 접근 방식을 지원합니다: 자동 생성 ID(소스 메시지 콘텐츠에서 파생됨)와 명시적 ID(개발자가 정의한 키). 두 방식 모두 PO 파일과 함께 작동합니다.

import { Trans } from "@lingui/react/macro";

// Auto-generated ID (from message content)
<Trans>Welcome to our platform</Trans>

// Explicit ID (developer-defined key)
<Trans id="nav.welcome">Welcome to our platform</Trans>

번역가와 AI를 위한 컨텍스트 추가

모든 매크로에서 comment prop을 사용하여 설명을 추가하세요. 이 주석은 번역가 노트로 PO 파일에 추출되어 메시지가 어디에 어떻게 나타나는지에 대한 중요한 컨텍스트를 제공합니다.

import { Trans } from "@lingui/react/macro";

<Trans comment="Shown on the homepage hero section above the fold">
  Start building with confidence
</Trans>
메시지 설명은 AI 기반 번역에 특히 유용합니다. AI가 짧은 UI 문자열을 구분하는 데 필요한 컨텍스트를 제공하여 일반적인 번역을 정확하고 맥락을 고려한 번역으로 바꿔줍니다.

복수형 처리

Lingui는 복수형 처리를 위해 모든 CLDR 복수형 범주를 지원하는 ICU MessageFormat을 사용합니다. Plural 매크로를 사용하면 JSX에서 다양한 복수형을 쉽게 처리할 수 있습니다:

  • value, one, other 및 선택적인 정확한 형식(_0, _2 등)과 함께 Plural 컴포넌트를 사용하세요.
  • # 플레이스홀더는 자동으로 복수형 값으로 대체됩니다.
  • l10n.dev는 아랍어(6개 형식), 러시아어, 폴란드어와 같이 복잡한 언어를 포함하여 모든 대상 언어에 필요한 모든 복수형 형식을 수동 개입 없이 생성합니다.
import { Plural } from "@lingui/react/macro";

function CartSummary({ itemCount }) {
  return (
    <p>
      <Plural
        value={itemCount}
        _0="Your cart is empty"
        one="You have # item in your cart"
        other="You have # items in your cart"
      />
    </p>
  );
}

런타임 초기화

메시지를 추출하고 컴파일한 후, i18n 인스턴스를 설정하고 앱을 I18nProvider로 감싸세요.

i18n 모듈 설정

컴파일된 메시지 카탈로그를 동적으로 로드하는 i18n 모듈을 생성하세요. Lingui Vite 플러그인은 개발 중에 즉석에서 컴파일되는 PO 파일의 직접 가져오기를 가능하게 합니다:

// src/i18n.ts
import { i18n } from "@lingui/core";

export async function loadCatalog(locale: string) {
  const { messages } = await import(`./locales/${locale}/messages.po`);
  i18n.load(locale, messages);
  i18n.activate(locale);
}

// Initialize with default locale
loadCatalog("en");

export default i18n;

I18nProvider 설정

전체 앱을 I18nProvider로 감싸서 React 컨텍스트를 통해 모든 컴포넌트에서 번역을 사용할 수 있도록 하세요:

// src/App.tsx
import { I18nProvider } from "@lingui/react";
import { i18n } from "./i18n";

function App() {
  return (
    <I18nProvider i18n={i18n}>
      <YourAppContent />
    </I18nProvider>
  );
}

런타임 언어 전환

언어 전환은 간단합니다: 새 카탈로그를 로드하고 로케일을 활성화하면 React가 자동으로 모든 번역된 콘텐츠를 다시 렌더링합니다. 다음은 완전한 언어 전환 컴포넌트 예시입니다:

import { useState } from "react";
import { loadCatalog } from "./i18n";
import { Trans } from "@lingui/react/macro";

const LANGUAGES = {
  en: "English",
  fr: "Français",
  de: "Deutsch",
  ja: "日本語",
  es: "Español",
};

function LanguageSwitcher() {
  const [currentLocale, setCurrentLocale] = useState("en");

  const handleChange = async (locale: string) => {
    await loadCatalog(locale);
    setCurrentLocale(locale);
  };

  return (
    <select
      value={currentLocale}
      onChange={(e) => handleChange(e.target.value)}
    >
      {Object.entries(LANGUAGES).map(([code, name]) => (
        <option key={code} value={code}>
          {name}
        </option>
      ))}
    </select>
  );
}

추출 및 컴파일 워크플로우

Lingui의 CLI는 번역 워크플로우의 핵심인 두 가지 주요 명령을 제공합니다: 소스 코드에서 PO 카탈로그로 메시지를 가져오는 extract와 PO 파일을 프로덕션용 최적화된 JavaScript 모듈로 변환하는 compile입니다.

# Extract messages from source code into PO catalogs
npx lingui extract

# Translate your PO files (manually, with a TMS, or with AI)

# Compile PO catalogs into optimized JS modules for production
npx lingui compile
  1. 추출(Extract): 소스 파일을 스캔하여 번역 가능한 모든 메시지로 PO 카탈로그를 생성하거나 업데이트합니다.
  2. 번역(Translate): PO 파일의 msgstr 필드를 수동으로, TMS를 사용하여, 또는 AI 기반 번역으로 채우세요.
  3. 컴파일(Compile): PO 카탈로그를 런타임에 로드되는 가벼운 JS 모듈로 변환합니다. 번역된 메시지만 포함됩니다.

l10n.dev의 완벽한 PO 지원

l10n.dev는 PO 파일에 대한 기본 지원을 제공하여 Lingui.js 프로젝트의 완벽한 동반자가 됩니다. 소스 PO 카탈로그를 업로드하고 정확하게 번역된 파일을 돌려받으세요:

  • 기본 PO 형식: PO 파일을 직접 업로드하세요. l10n.dev는 msgid 항목을 읽고 번역한 다음 올바른 msgstr 값으로 적절하게 포맷된 PO 파일을 다시 작성합니다.
  • ICU MessageFormat 인식: 플레이스홀더({name}), 인덱스 태그(<0>), 복수형 및 선택 표현식이 모든 번역에서 올바르게 보존됩니다.
  • 컨텍스트 인식 AI 번역: 번역가 주석(#.)과 메시지 컨텍스트(msgctxt)가 AI에 의해 사용되어 더 정확하고 맥락을 고려한 번역을 생성합니다.
  • 복수형 생성: 모든 대상 언어에 대해 필요한 모든 CLDR 복수형 형식이 생성됩니다. 복잡한 복수형 규칙을 가진 언어(아랍어, 러시아어, 폴란드어)도 자동으로 처리됩니다.
  • 일괄 및 증분 업데이트: 카탈로그 전체를 한 번에 번역하거나 --update 플래그를 사용하여 기존 번역을 보존하면서 새 메시지와 변경된 메시지만 번역하세요.

npm을 통한 번역 자동화

ai-l10n npm 패키지를 사용하여 명령줄에서 또는 CI/CD 파이프라인의 일부로 Lingui PO 카탈로그를 번역하세요. 한 번 설치하면 단일 명령으로 원하는 수의 언어로 번역할 수 있습니다.

# Install the CLI
npm install ai-l10n

# Translate your source PO file to multiple languages
npx ai-l10n translate src/locales/en/messages.po \
  --languages fr,de,ja,zh-CN,es,ko

빌드 프로세스 통합

ai-l10n을 Lingui 빌드 프로세스에 직접 연결하여 항상 최신 상태의 번역을 유지하세요. 추출, 번역, 컴파일을 단일 워크플로우로 결합하세요.

package.json 스크립트 사용

extract, translate, compile을 스크립트로 추가하고 연결하세요. i18n 스크립트는 전체 파이프라인을 실행합니다. 배포 전에 번역이 항상 최신 상태인지 확인하기 위해 prebuild에서 사용하세요.

{
  "scripts": {
    "extract": "lingui extract",
    "compile": "lingui compile",
    "translate": "ai-l10n translate src/locales/en/messages.po --languages fr,de,ja,zh-CN,es,ko --update",
    "i18n": "npm run extract && npm run translate && npm run compile",
    "prebuild": "npm run i18n",
    "build": "vite build",
    "dev": "vite"
  }
}

Makefile 사용

팀에서 Make를 사용하는 경우, 추출, 번역 및 컴파일을 적절한 종속성이 있는 별도의 타겟으로 선언하세요:

LANGUAGES = fr,de,ja,zh-CN,es,ko

extract:
	npx lingui extract

translate:
	npx ai-l10n translate src/locales/en/messages.po --languages $(LANGUAGES) --update

compile:
	npx lingui compile

i18n: extract translate compile

dev: i18n
	npx vite

build: i18n
	npx vite build

CI/CD 통합, 증분 업데이트, 여러 파일에 대한 일괄 번역 및 GitHub Actions 워크플로우 예제에 대해서는 다음을 참조하세요: 현지화 자동화 가이드.

VS Code 확장 프로그램

l10n.dev VS Code 확장 프로그램은 PO 파일 번역을 에디터로 직접 가져옵니다. VS Code를 떠나지 않고 Lingui 카탈로그를 번역하세요.

VS Code에서 작동 방식:

  1. 에디터에서 소스 PO 파일(예: src/locales/en/messages.po)을 엽니다.
  2. 에디터에서 마우스 오른쪽 버튼을 클릭하고 "Translate..."를 선택합니다(PO 파일에서도 작동).
  3. 하나 이상의 대상 언어(예: 프랑스어, 일본어, 독일어)를 선택합니다.
  4. 확장 프로그램이 해당 로케일 폴더에 번역된 PO 파일을 생성하며, 컴파일할 준비가 완료됩니다.

Lingui로 React 앱 현지화 시작하기

전 세계 사용자에게 다가갈 준비가 되셨나요? l10n.dev 워크스페이스에서 직접 Lingui PO 파일을 번역하거나, npm CLI로 자동화하거나, VS Code 내에서 바로 번역하세요: