형식

Max PrilutskiyCEO 겸 공동창업자Updated 16일 전 · 5 min read

CLI는 18가지 파일 형식을 번역합니다. 형식은 파일 확장자로 자동 판별되며, 이를 덮어쓰려면 format 항목에 files[]을 설정하세요. 또는 항상 이 설정이 필요한 세 가지 형식(yaml-openapi, yaml-root-key, android)에도 지정해야 합니다.

형식확장자format참고
JSON.jsonjson키/값 형식. key controls를 지원합니다.
JSONC.jsoncjsonc주석이 포함된 JSON. 주석은 유지되며 translator notes 역할도 합니다.
YAML.yaml, .ymlyaml일반 YAML입니다. 모든 문자열 값이 번역되고 키와 구조는 그대로 유지됩니다.
OpenAPI YAML.yaml, .ymlyaml-openapiOpenAPI 스펙입니다. format을 명시적으로 설정하세요. 일반 .yaml는 자동 감지 시 yaml로 처리됩니다.
로캘 루트 키 YAML.yaml, .ymlyaml-root-key로캘은 YAML의 루트 키입니다(Rails config/locales). 루트 키는 대상 로캘로 다시 작성됩니다. format를 명시적으로 설정하세요.
Markdown.mdmd본문은 번역되며, frontmatter는 opt-in입니다.
MDX.mdxmdxMarkdown + JSX. 컴포넌트 props는 opt-in입니다.
Markdoc.mdocmarkdocMarkdown + 태그. frontmatter와 태그 속성을 지원합니다.
TypeScript.ts, .mts, .ctstypescript로캘 모듈(export default { … })입니다. 문자열 리터럴은 번역되고 코드는 유지됩니다.
Gettext PO.popomsgstr는 번역되며, msgid, 주석, 헤더는 유지됩니다.
Flutter ARB.arbflutter문자열 값은 번역되며 @ 메타데이터와 {placeholders}는 유지됩니다.
Android.xmlandroidstrings.xml 형식입니다. format를 명시적으로 설정하세요. .xml는 자동 감지되지 않습니다.
Xcode strings.stringsxcode-strings값은 번역되고 키는 유지됩니다.
Xcode String Catalog.xcstringsxcode-xcstrings하나의 파일에 모든 로캘이 들어 있습니다. 타깃은 같은 파일에 다시 기록됩니다(아래 참고).
Xcode stringsdict.stringsdictxcode-stringsdict복수형 문자열은 번역되고 형식 제어 키는 유지됩니다.
XLIFF.xlf, .xliffxliff<source>는 유지되고, <target>는 유닛별로 기록됩니다. 버전 1.2와 2.0을 지원합니다.
SubRip.srtsrt자막 텍스트는 번역되며 인덱스와 타임코드는 그대로 유지됩니다.
PHP.phpphpLaravel return [ … ] 형식입니다. 문자열 값은 번역되고 키, 숫자, 구조는 유지됩니다.

처음부터 끝까지 살펴보기

데모 프로젝트는 문서 및 데이터 형식(JSON, JSONC, Markdown, MDX, Markdoc, OpenAPI YAML)과 각 형식에 꼭 필요한 설정만 담아둔 작은 Sandbox입니다. npx degit lingodotdev/lingo.dev/demo/new-cli my-lingo-demo로 복제한 뒤 push를 실행하세요. 앱 및 프레임워크 형식은 여기에는 포함되어 있지 않습니다. 해당 형식은 Example projects에서 프레임워크별 전체 저장소를 제공하며, 아래 형식별 스니펫에서 관련 설정을 확인할 수 있습니다.

bash
npx degit lingodotdev/lingo.dev/demo/new-cli my-lingo-demo
cd my-lingo-demo

JSON 및 JSONC#

기본적인 키/값 번역입니다. key control로 따로 지정하지 않는 한 모든 문자열 값이 번역됩니다.

json
{ "pattern": "content/en/app.json", "lockedKeys": ["meta.version"] }

JSONC는 주석도 함께 보존하며, 엔진은 이를 문맥 정보로 활용합니다. 자세한 내용은 translator notes를 참고하세요.

json
{ "pattern": "content/en/settings.jsonc", "preservedKeys": ["featureFlags"] }

Markdown, MDX, Markdoc#

본문은 기본적으로 번역됩니다. frontmatter와 임베드된 컴포넌트는 직접 opt-in하지 않으면 번역되지 않습니다.

Frontmatter#

번역할 frontmatter 필드는 translateFrontmatterFields에 나열하세요:

json
{
  "pattern": "content/en/guide.md",
  "translateFrontmatterFields": ["title", "description"]
}

MDX 컴포넌트 props#

MDX에서는 translateComponentProps를 사용해 특정 컴포넌트의 특정 props만 번역할 수 있습니다:

json
{
  "pattern": "content/en/landing.mdx",
  "translateFrontmatterFields": ["title"],
  "translateComponentProps": [{ "component": ["Hero", "Callout"], "props": ["title", "body"] }]
}

이렇게 하면 titlebody<Hero><Callout> props만 번역되고, 나머지 props는 모두 그대로 유지됩니다.

Markdoc#

Markdoc는 Markdown과 비슷하게 동작하며, frontmatter와 태그 속성은 유지됩니다:

json
{
  "pattern": "content/en/changelog.mdoc",
  "translateFrontmatterFields": ["title"]
}

YAML#

일반 YAML은 .yaml/.yml 확장자로 자동 감지됩니다. 모든 문자열 값이 번역되고 키와 구조는 유지됩니다:

json
{ "pattern": "content/en/strings.yaml" }

OpenAPI 스펙은 예외입니다. .yaml 확장자를 함께 쓰지만, 엔진이 사용자에게 노출되는 필드(요약, 설명)만 번역하고 스키마 키, 경로, operation ID는 그대로 두려면 format를 명시적으로 지정해야 합니다:

json
{ "pattern": "content/en/api.yaml", "format": "yaml-openapi" }

Rails 스타일 로캘 파일은 또 다른 예외입니다. 로캘이 YAML의 루트 키(en:)이며, 대상 파일도 대상 로캘(es:)을 루트로 가져야 합니다. 이 경우에도 format를 명시적으로 설정하세요:

json
{ "pattern": "config/locales/en.yml", "format": "yaml-root-key" }

앱 및 프레임워크 형식#

PO, Flutter ARB, Xcode .strings, Xcode .stringsdict, TypeScript 로캘 모듈, XLIFF, SubRip, PHP는 모두 같은 원칙을 따릅니다. 번역 가능한 텍스트만 번역하고, 구조적 요소는 모두 유지합니다(키, ID, 메타데이터, 플레이스홀더, 타임코드, 코드, 서식). 각 형식은 확장자로 자동 감지되므로 소스 파일을 가리키는 패턴만 지정하면 됩니다:

json
{ "pattern": "lib/l10n/app_en.arb" }
{ "pattern": "locales/en.po" }
{ "pattern": "Localizable.strings" }
{ "pattern": "l10n/en.xlf" }

다만 확장자가 너무 모호해 자동 감지할 수 없는 형식이 하나 있어, 이 경우에는 format를 명시적으로 지정해야 합니다:

json
{ "pattern": "res/values/strings.xml", "format": "android" }

Xcode String Catalogs#

.xcstrings(String Catalog) 파일은 모든 로캘을 하나의 파일에 담습니다. 로캘별 출력 경로는 없으며, CLI가 소스 로캘을 읽은 뒤 모든 타깃을 같은 파일에 다시 기록합니다:

json
{ "pattern": "Localizable.xcstrings" }

카탈로그에서 "shouldTranslate": false로 표시된 문자열은 건너뜁니다 — CLI는 해당 문자열을 번역하지 않고 손대지 않은 채로 둡니다.

키 스코프를 지원하는 형식은 무엇인가요?#

lingo push --key는 지정한 키만 다시 번역하고, 나머지는 그대로 둡니다. 이 기능을 사용하려면 키가 바뀌지 않는 안정적인 이름이어야 하고, 파일은 특정 키가 없어도 문제없는 구조여야 합니다. 그래서 문서 형식과 복수형 사전에는 사용할 수 없습니다:

키 스코프 지원키 스코프 비지원
json, jsonc, yaml, yaml-root-key, po, flutter, android, xcode-strings, xcode-xcstrings, xliff, php, typescriptmd, mdx, markdoc, html, srt, yaml-openapi, xcode-stringsdict

md, mdx, markdoc, html, srt, yaml-openapi에서는 각 단위가 문서 안에서의 위치(섹션 순번, 노드 경로, 자막 큐 번호 등)로 식별됩니다. 그래서 위쪽 내용이 조금만 수정돼도 해당 키가 바로 달라집니다. 이 때문에 그중 하나를 대상으로 범위를 지정하면 엉뚱한 문자열이 선택되거나 아무것도 선택되지 않을 수 있습니다. xcode-stringsdict은 반대로, 파일이 유효한 복수형 사전으로 유지되려면 키인 복수 범주가 반드시 모두 있어야 하므로 지원되지 않습니다.

lingo push는 키 범위를 지정한 실행에서 지원되지 않는 파일이 있더라도 작업을 실패로 처리하지 않고, 경고를 보여준 뒤 해당 파일만 제외합니다. 따라서 push할 때 이런 파일을 키-값 파일과 함께 섞어도 괜찮습니다. 이런 파일은 --key 없이 push하세요.

지원되는 형식 안에 있는 위치 기반 멤버도 마찬가지로 동작하며, 스코프가 적용되면 원문 텍스트 기준으로 유지됩니다. 여기에는 배열 요소, Android <string-array> 항목, <plurals> 수량 항목이 포함됩니다.

출력 경로#

이 패턴은 소스 파일의 이름을 기준으로 하며, 모든 대상 경로는 여기서 파생됩니다. 다음 네 가지 규칙이 순서대로 적용됩니다:

  1. 경로 세그먼트 전체 또는 파일명 자체가 로캘인 경우 — 가장 일반적인 케이스입니다. content/en/app.jsoncontent/de/app.json, locales/en.jsonlocales/de.json.
  2. 세그먼트나 파일명 끝에 로캘이 붙는 경우 — Android, Xcode .strings/.stringsdict, Flutter, yaml-root-key처럼 이런 형식을 쓰는 레이아웃에 해당합니다. res/values-en/res/values-de/, app_en.arbapp_de.arb, devise.en.ymldevise.de.yml.
  3. 경로에 로캘이 전혀 없고, 플랫폼이 기본 언어에 예약해 둔 이름을 쓰는 경우입니다. Android의 기본 res/values/res/values-de/가 되고, Xcode의 Base.lprojde.lproj가 됩니다.
  4. String Catalog의 경우, 하나의 파일에 모든 로캘이 들어 있으므로 대상 경로는 소스 경로와 동일합니다.

대상 경로가 BCP 47을 따르지 않는 플랫폼은 Android뿐입니다. CLI는 Android가 실제로 읽는 리소스 한정자를 기록하므로, pt-BRvalues-pt-rBR/로, zh-Hansvalues-b+zh+Hans/로 들어갑니다.

어느 규칙에도 맞지 않아 소스 로캘이 경로 어디에도 나타나지 않으면, CLI는 대체 동작으로 파일 옆에 <locale>/ 디렉터리를 만들어 넣고, lingo push를 통해 추측한 결과임을 알려줍니다. 이 경고는 패턴이 잘못되었다는 신호로 받아들이세요. Configuration을 참고하세요.

레거시 CLI를 사용 중이신가요?#

레거시 CLI의 주요 형식 대부분은 이제 현재 CLI에서도 지원됩니다(PO, XLIFF, Android/Xcode strings, Flutter ARB 등 — 위 표 참고). 다만 비교적 덜 쓰이는 일부 형식(예: CSV, HTML, MJML, .properties)은 아직 지원되지 않습니다. 해당 형식이 추가되기 전까지는 legacy CLI docs를 참고하세요.