설정
Rosetta는 설정 없이(zero-config) 작동해요. 프로젝트에서 로케일 파일, 형식, 대상 언어를 자동으로 감지하거든요. 더 세밀하게 제어하려면 프로젝트 루트에 i18n-rosetta.config.json 파일을 만들거나 다음 명령을 실행하세요:
npx i18n-rosetta init
전체 설정 참조
{
"version": 3,
"inputLocale": "en",
"localesDir": "./locales",
"contentDir": null,
"translatableFields": null,
"format": "auto",
"model": "google/gemini-3.5-flash",
"defaultMethod": "llm",
"batchSize": 80,
"jsonConcurrency": 200,
"contentConcurrency": 48,
"fallbackPrefix": "[EN] ",
"apiKeyEnvVar": "OPENROUTER_API_KEY",
"baseUrl": "",
"pairs": {},
"languages": {},
"lint": {
"srcDir": null,
"ignore": ["node_modules", ".next", "dist"],
"minLength": 2
},
"seo": {
"urlPattern": "/:locale/:path",
"pages": null
},
"typegen": {
"output": null,
"autoGenerate": false
}
}
:::note typegen은 아직 구현되지 않았어요
설정 로더가 typegen 설정 블록을 인식하고 유지하지만, TypeScript 타입 생성은 아직 구현되지 않았어요. 이는 향후 추가될 기능을 위한 자리 표시자(placeholder)예요. 이 값들을 설정해도 아무런 효과가 없어요.
:::
필드
| 필드 | 타입 | 기본값 | 설명 |
|---|---|---|---|
version | number | 3 | 설정 스키마 버전이에요. 항상 3을 사용해요. |
inputLocale | string | "en" | 소스 언어 코드예요 (BCP 47). |
localesDir | string | "./locales" | 로케일 파일 경로예요. Rosetta가 이 디렉터리를 스캔해요. |
contentDir | string | null | Hugo 콘텐츠 디렉터리예요. Markdown 본문 번역을 활성화해요. |
translatableFields | string[] | null | 콘텐츠 번역 시 번역 가능한 기본 frontmatter 필드를 재정의해요. null은 내장된 기본값(title, description, summary)을 사용해요. |
format | string | "auto" | 파일 형식이에요: json, toml, yaml, 또는 auto (확장자에서 감지해요). |
model | string | "google/gemini-3.5-flash" | LLM 메서드의 기본 모델이에요. 형식은 메서드에 따라 달라요: OpenRouter는 provider/model를 사용하고(예: google/gemini-3.5-flash), 직접 제공자는 기본 이름만 사용해요(예: gpt-4o, gemini-2.5-flash). |
defaultMethod | string | "llm" | 기본 번역 메서드예요: llm, llm-coached, google-translate, deepl, microsoft-translator, libretranslate, openai, anthropic, gemini, api. --method CLI 플래그로 재정의할 수 있어요. |
batchSize | number | 80 | 번역 배치당 키 개수예요. 높을수록 API 호출 횟수는 줄어들지만 프롬프트 크기가 커져요. |
jsonConcurrency | number | 200 | JSON 키 동기화를 위한 최대 병렬 로케일 번역 수예요. --json-concurrency CLI 플래그로 재정의할 수 있어요. |
contentConcurrency | number | 48 | 콘텐츠(Markdown/MDX) 번역을 위한 최대 병렬 API 호출 수예요. --content-concurrency CLI 플래그로 재정의할 수 있어요. |
fallbackPrefix | string | "[EN] " | audit 및 verify이 이전 실행에서 번역되지 않은 레거시 값을 감지하는 데 사용하는 마커 접두사예요. Rosetta는 이 접두사를 쓰지 않고 감지를 위해 읽기만 해요. |
apiKeyEnvVar | string | "OPENROUTER_API_KEY" | API 키의 환경 변수 이름이에요. 사용자 지정 환경 변수 이름을 사용하려면 재정의하세요. |
baseUrl | string | "" | SEO 아티팩트 생성(hreflang, sitemaps, JSON-LD)을 위한 기본 URL이에요. |
pairs | object | {} | 쌍(pair)별 메서드, 모델, 품질 재정의예요. 쌍 설정(Pair Configuration)을 참고하세요. |
languages | object | {} | 언어별 재정의예요. 언어 설정(Language Configuration)을 참고하세요. |
lint.srcDir | string | null | 린트 스캔을 위한 소스 디렉터리예요. null = 프레임워크에서 자동 감지해요. |
lint.ignore | string[] | ["node_modules", ...] | 린트에서 제외할 Glob 패턴이에요. |
lint.minLength | number | 2 | 하드코딩된 것으로 표시할 최소 문자열 길이예요. |
seo.urlPattern | string | "/:locale/:path" | hreflang 태그 생성을 위한 URL 패턴 템플릿이에요. |
seo.pages | string[] | null | SEO를 위한 명시적 페이지 목록이에요. null = 로케일 키에서 자동 감지해요. |
typegen.output | string | null | 생성된 TypeScript 타입의 출력 경로예요. null = 비활성화돼요. |
typegen.autoGenerate | boolean | false | 각 동기화 후 타입을 자동으로 다시 생성해요. |
쌍 설정 (Pair Configuration)
각 소스→대상 쌍은 독립적으로 설정할 수 있어요:
{
"pairs": {
"en:fr": {
"method": "google-translate",
"qualityTier": "high"
},
"en:ja": {
"method": "llm",
"model": "google/gemini-2.5-pro"
},
"en:crk": {
"methodPlugin": "crk-coached-v1"
}
}
}
쌍 필드
| 필드 | 타입 | 설명 |
|---|---|---|
method | string | 번역 메서드예요: llm, llm-coached, google-translate, deepl, microsoft-translator, libretranslate, openai, anthropic, gemini, api |
methodPlugin | string | 설치된 플러그인 이름이에요 (.rosetta/methods/에서 가져옴) |
model | string | 이 쌍의 기본 모델을 재정의해요 |
endpoint | string | 원격 API 엔드포인트 URL이에요. method이 api일 때 필수예요. |
qualityTier | string | 표시 티어예요: standard, high, research, verified |
언어 설정
언어는 세 가지 형식을 허용해요:
코드 배열 (가장 간단함)
{
"languages": ["fr", "de", "ja"]
}
각 언어는 내장된 레지스터 테이블에서 기본 레지스터(register)를 가져와요. 기본값이 없는 언어는 "Professional register."을 사용해요.
레지스터 문자열이 있는 객체
값은 언어 카드의 **프리셋 키(preset key)**이거나 사용자 지정 레지스터 텍스트일 수 있어요:
{
"languages": {
"fr": "casual-tu",
"ko": "formal-hapsyo",
"ja": "Custom: Polite Japanese for a gaming app."
}
}
Rosetta는 문자열이 언어 카드의 프리셋 키와 일치하는지 확인해요. 일치하면 카드의 전체 레지스터 프롬프트를 사용해요. 그렇지 않으면 문자열을 그대로 사용해요. 사용 가능한 프리셋은 지원되는 언어(Supported Languages)를 참고하세요.
전체 설정이 있는 객체
{
"languages": {
"crk": {
"name": "Plains Cree",
"register": "SRO syllabics with grammatical precision.",
"model": "google/gemini-2.5-pro",
"batchSize": 5,
"maxRetries": 5,
"script": "cans"
}
}
}
동일한 블록 내에서 약식과 전체 객체를 섞어서 사용할 수 있어요.
언어 필드
| 필드 | 타입 | 설명 |
|---|---|---|
register | string | 스타일/어조 지침이에요. 프리셋 키(예: casual-tu, formal-hapsyo) 또는 사용자 지정 텍스트일 수 있어요. 언어 카드(Language Cards)를 참고하세요. |
name | string | 사람이 읽을 수 있는 언어 이름이에요 (상태 표시용) |
model | string | 기본 모델을 재정의해요 |
batchSize | number | 기본 배치 크기를 재정의해요 |
maxRetries | number | 실패한 배치에 대한 최대 재시도 횟수예요 (기본값: 3) |
script | string | ISO 15924 스크립트 코드예요. 품질 게이트(quality gate)에서 스크립트 유효성 검사를 트리거해요. |
:::info 상속 체인 설정은 다음 순서로 확인돼요 (먼저 적용된 것이 우선):
쌍(pair) 수준 → 언어 수준 → 전역 설정 → 기본값
예를 들어, pairs["en:fr"]에서 model을 설정하면, 언어 수준과 전역 model 값을 모두 재정의해요.
:::
영어가 아닌 소스
소스 언어가 영어가 아닌 경우:
# CLI flag (one-time)
npx i18n-rosetta sync --source fr
{
"inputLocale": "fr"
}
잠금 파일 (Lock File)
Rosetta는 번역된 소스 값의 SHA-256 해시를 추적하기 위해 .i18n-rosetta.lock 파일을 생성해요. 모든 개발자가 동일한 번역 기준선을 공유할 수 있도록 이 파일을 커밋해 주세요.
소스 값이 변경되면 해시가 더 이상 일치하지 않으며, Rosetta는 다음 동기화 시 해당 키를 다시 번역해요.
.rosettaignore
lint 스캔에서 파일을 제외하려면 프로젝트 루트에 .rosettaignore 파일을 만드세요. .gitignore과 같은 glob 패턴을 사용해요:
src/components/legacy/**
src/utils/constants.js
**/*.test.js
.rosetta/ 디렉터리
Rosetta는 내부 상태를 위해 프로젝트 루트에 .rosetta/ 디렉터리를 생성해요. 이는 프로젝트 소스가 아닌 로컬 최적화이므로, 일반적으로 .gitignore에 추가해야 해요:
.rosetta/
| 파일 | 목적 | 커밋 여부 |
|---|---|---|
tm.json | 번역 메모리 캐시 — 소스 텍스트 + 로케일 + 메서드를 키로 사용하여 이전 번역을 저장해요 | 아니요 (로컬 캐시) |
xliff/*.xliff | 전문 번역가 검토를 위한 XLIFF 내보내기 파일이에요 | 아니요 (임시 파일) |
methods/ | 설치된 메서드 플러그인 매니페스트예요 | 예 (공유 설정) |
backups/ | 래핑 전 백업이에요 (wrap --undo에 의해 생성됨) | 아니요 (안전망) |
tm.json에 대한 자세한 내용과 API 비용을 절감하는 방법은 번역 메모리(Translation Memory)를 참고하세요.
프로그래밍 방식 API
빌드 스크립트 및 사용자 지정 통합을 위해 패키지에서 직접 가져오세요:
import { GeminiMethod, runSync, resolveConfig } from 'i18n-rosetta';
// Use a method class directly
const gemini = new GeminiMethod();
const result = await gemini.translate(
['greeting', 'farewell'],
{ greeting: 'Hello', farewell: 'Goodbye' },
{ target: 'fr', name: 'French', register: 'formal', model: 'gemini-2.5-flash' },
{ cwd: process.cwd() }
);
// result = { greeting: 'Bonjour', farewell: 'Au revoir' }
사용 가능한 내보내기(Exports)
| 내보내기 | 기능 |
|---|---|
TranslationMethod | 모든 메서드의 기본 클래스예요 |
LLMMethod | LLM 메서드(OpenRouter)의 기본 클래스예요 |
DirectLLMMethod | 직접 LLM 제공자(OpenAI, Anthropic, Gemini)의 기본 클래스예요 |
OpenAIMethod, AnthropicMethod, GeminiMethod | 직접 LLM 제공자 클래스예요 |
DeepLMethod, MicrosoftTranslatorMethod, LibreTranslateMethod | 전통적인 기계 번역(MT) 클래스예요 |
GoogleTranslateMethod | Google Cloud Translation이에요 |
LLMCoachedMethod | 코칭된 LLM(OpenRouter + 코칭 데이터)이에요 |
APIMethod | 원격 API 클라이언트예요 |
runSync, runContentSync | 전체 동기화 파이프라인이에요 |
resolveConfig, resolvePairs | 설정 확인(resolution)이에요 |
validateTranslations | 품질 게이트(Quality gate)예요 |
loadCoachingData, findDictionaryMatches | 코칭 유틸리티예요 |
사용자 지정 제공자 확장
DirectLLMMethod를 확장하여 약 40줄의 코드로 새로운 LLM 제공자를 추가할 수 있어요:
import { DirectLLMMethod } from 'i18n-rosetta';
class MistralMethod extends DirectLLMMethod {
constructor(options) {
super(options);
this.name = 'mistral';
}
_getApiKeyEnvVar() { return 'MISTRAL_API_KEY'; }
_getApiKeyOptionsKey() { return 'mistralApiKey'; }
_getDefaultModel() { return 'mistral-large-latest'; }
_getProviderLabel() { return 'Mistral'; }
_buildApiRequest({ prompt, systemMessage, apiKey, model, temperature }) {
return {
url: 'https://api.mistral.ai/v1/chat/completions',
headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' },
body: {
model,
messages: [
...(systemMessage ? [{ role: 'system', content: systemMessage }] : []),
{ role: 'user', content: prompt },
],
temperature,
},
};
}
_extractResponseText(json) {
return json.choices?.[0]?.message?.content;
}
// Optional but recommended: provider-specific setup help when translation fails
getSetupHelp() {
if (!process.env.MISTRAL_API_KEY) {
return [
'',
' ┌─ Missing API Key ─────────────────────────────────────────────┐',
' │ Mistral requires an API key from https://console.mistral.ai │',
' │ Run: export MISTRAL_API_KEY=... │',
' └────────────────────────────────────────────────────────────────┘',
];
}
return [' API key is set but translation failed. Check your Mistral dashboard.'];
}
}
번역, 코칭, 재시도 루프, 모델 유효성 검사, 품질 티어 및 설정 도움말이 기본으로 제공돼요. HTTP 요청 형태만 제공자에 따라 달라요. 원시 fetch()를 사용하는 비 LLM 어댑터의 경우, 자체 재시도 루프를 작성하는 대신 lib/methods/fetch-with-retry.js의 공유 fetchWithRetry() 헬퍼를 사용하세요.
참고 항목
- CLI 참조(CLI Reference) — 모든 명령 및 플래그
- 번역 메서드(Translation Methods) — 메서드 선택 및 혼합
- 번역 메모리(Translation Memory) — 캐싱 및 비용 절감
- 전문 번역가와 협업하기(Working with Professional Translators) — XLIFF 워크플로
- 플러그인 사양(Plugin Specification) — 메서드 플러그인 매니페스트 형식
- 아키텍처(Architecture) — 구성 요소 연결 방식
- 지원되는 언어(Supported Languages) — 내장된 언어 지원
- 동기화 작동 방식(How Sync Works) — 번역 파이프라인