문서 목차
이 페이지에서목차

slang-i18n Templates

Internationalization translation pattern templates.

Internationalization translation pattern templates.


Template A: Basic Translation Structure#

ko.i18n.json (Korean, base)#

{
  "common": {
    "app_name": "Unibook",
    "ok": "확인",
    "cancel": "취소",
    "save": "저장",
    "delete": "삭제",
    "edit": "수정",
    "close": "닫기",
    "loading": "로딩 중...",
    "error": "오류가 발생했습니다",
    "retry": "다시 시도",
    "no_data": "데이터가 없습니다"
  },
  "auth": {
    "login": "로그인",
    "logout": "로그아웃",
    "sign_up": "회원가입",
    "email": "이메일",
    "password": "비밀번호",
    "forgot_password": "비밀번호를 잊으셨나요?"
  },
  "navigation": {
    "home": "홈",
    "search": "검색",
    "mypage": "마이페이지",
    "settings": "설정"
  }
}

en.i18n.json (English)#

{
  "common": {
    "app_name": "Unibook",
    "ok": "OK",
    "cancel": "Cancel",
    "save": "Save",
    "delete": "Delete",
    "edit": "Edit",
    "close": "Close",
    "loading": "Loading...",
    "error": "An error occurred",
    "retry": "Retry",
    "no_data": "No data available"
  },
  "auth": {
    "login": "Login",
    "logout": "Logout",
    "sign_up": "Sign Up",
    "email": "Email",
    "password": "Password",
    "forgot_password": "Forgot password?"
  },
  "navigation": {
    "home": "Home",
    "search": "Search",
    "mypage": "My Page",
    "settings": "Settings"
  }
}

Template B: Parameter Patterns#

User Greetings#

{
  "user": {
    "greeting": "{name}님, 안녕하세요!",
    "welcome_back": "{name}님, 다시 오셨군요!",
    "member_since": "{date}에 가입",
    "points": "{count} 포인트 보유",
    "level_info": "{level} 등급 회원입니다"
  }
}

Dart Usage Example#

// User greeting
Text(context.i10n.user.greeting(name: user.displayName))

// Points display
Text(context.i10n.user.points(count: user.points.toString()))

// Join date display
Text(context.i10n.user.member_since(date: DateFormat('yyyy-MM-dd').format(user.createdAt)))

Template C: Pluralization Patterns#

Item Counts#

{
  "items": {
    "count(param=n)": {
      "zero": "항목 없음",
      "one": "항목 1개",
      "other": "항목 {n}개"
    }
  },
  "cart": {
    "item_count(param=count)": {
      "zero": "장바구니가 비어있습니다",
      "one": "장바구니에 상품 1개",
      "other": "장바구니에 상품 {count}개"
    }
  },
  "notifications": {
    "unread(param=count)": {
      "zero": "읽지 않은 알림 없음",
      "one": "읽지 않은 알림 1개",
      "other": "읽지 않은 알림 {count}개"
    }
  },
  "messages": {
    "count(param=n)": {
      "zero": "메시지 없음",
      "one": "메시지 1개",
      "other": "메시지 {n}개"
    }
  },
  "followers": {
    "count(param=n)": {
      "zero": "팔로워 없음",
      "one": "팔로워 1명",
      "other": "팔로워 {n}명"
    }
  }
}

Dart Usage Example#

// Cart item count
Text(context.i10n.cart.item_count(count: cartItems.length))

// Notification badge
Badge(
  label: Text(context.i10n.notifications.unread(count: unreadCount)),
)

// Follower count
Text(context.i10n.followers.count(n: followerCount))

Template D: Context-Based Patterns#

Enum-Based Translation#

{
  "pet": {
    "type(context=PetType)": {
      "dog": "강아지",
      "cat": "고양이",
      "bird": "새",
      "fish": "물고기",
      "hamster": "햄스터",
      "other": "기타"
    }
  },
  "order": {
    "status(context=OrderStatus)": {
      "pending": "대기 중",
      "confirmed": "확인됨",
      "shipping": "배송 중",
      "delivered": "배송 완료",
      "cancelled": "취소됨"
    }
  },
  "payment": {
    "method(context=PaymentMethod)": {
      "card": "카드 결제",
      "bank": "계좌이체",
      "kakao": "카카오페이",
      "naver": "네이버페이"
    }
  }
}

Dart Enum Definition#

// lib/domain/entity/pet_type.dart
enum PetType {
  dog,
  cat,
  bird,
  fish,
  hamster,
  other,
}

// Usage
Text(context.i10n.pet.type(context: pet.type))
Text(context.i10n.order.status(context: order.status))

Template E: Error Message Patterns#

Form Validation Errors#

{
  "validation": {
    "required": "필수 입력 항목입니다",
    "email": {
      "invalid": "올바른 이메일 형식이 아닙니다",
      "exists": "이미 사용 중인 이메일입니다"
    },
    "password": {
      "too_short": "비밀번호는 최소 8자 이상이어야 합니다",
      "too_weak": "비밀번호가 너무 약합니다",
      "mismatch": "비밀번호가 일치하지 않습니다"
    },
    "phone": {
      "invalid": "올바른 전화번호 형식이 아닙니다"
    }
  },
  "error": {
    "network": "네트워크 연결을 확인해주세요",
    "server": "서버 오류가 발생했습니다",
    "timeout": "요청 시간이 초과되었습니다",
    "unauthorized": "로그인이 필요합니다",
    "forbidden": "접근 권한이 없습니다",
    "not_found": "요청한 정보를 찾을 수 없습니다",
    "unknown": "알 수 없는 오류가 발생했습니다"
  }
}

Dart Usage Example#

// Form validation
TextFormField(
  validator: (value) {
    if (value == null || value.isEmpty) {
      return context.i10n.validation.required;
    }
    if (!EmailValidator.validate(value)) {
      return context.i10n.validation.email.invalid;
    }
    return null;
  },
)

// Error handling
result.fold(
  (failure) => ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(content: Text(context.i10n.error.network)),
  ),
  (success) => navigateToHome(),
);

Template F: Date/Time Patterns#

Relative Time#

{
  "time": {
    "just_now": "방금 전",
    "minutes_ago": "{minutes}분 전",
    "hours_ago": "{hours}시간 전",
    "days_ago": "{days}일 전",
    "weeks_ago": "{weeks}주 전",
    "months_ago": "{months}개월 전",
    "years_ago": "{years}년 전",
    "in_minutes": "{minutes}분 후",
    "in_hours": "{hours}시간 후",
    "in_days": "{days}일 후"
  }
}

Dart Usage Example#

String getRelativeTime(BuildContext context, DateTime dateTime) {
  final now = DateTime.now();
  final difference = now.difference(dateTime);

  if (difference.inMinutes < 1) {
    return context.i10n.time.just_now;
  } else if (difference.inMinutes < 60) {
    return context.i10n.time.minutes_ago(minutes: difference.inMinutes.toString());
  } else if (difference.inHours < 24) {
    return context.i10n.time.hours_ago(hours: difference.inHours.toString());
  } else if (difference.inDays < 7) {
    return context.i10n.time.days_ago(days: difference.inDays.toString());
  } else if (difference.inDays < 30) {
    return context.i10n.time.weeks_ago(weeks: (difference.inDays ~/ 7).toString());
  } else if (difference.inDays < 365) {
    return context.i10n.time.months_ago(months: (difference.inDays ~/ 30).toString());
  } else {
    return context.i10n.time.years_ago(years: (difference.inDays ~/ 365).toString());
  }
}

Template G: Rich Text Patterns#

{
  "legal": {
    "terms_agreement": "이용약관에 동의합니다. <link>자세히 보기</link>",
    "privacy_agreement": "개인정보 처리방침에 동의합니다. <link>자세히 보기</link>"
  },
  "marketing": {
    "promotion": "<highlight>특별 할인</highlight> 이벤트가 진행 중입니다!",
    "new_feature": "새로운 기능이 추가되었습니다. <link>확인하기</link>"
  }
}

Dart Usage Example#

// Rich text builder
Text.rich(
  context.i10n.legal.terms_agreement(
    link: (text) => TextSpan(
      text: text,
      style: TextStyle(
        color: AppColors.primary,
        decoration: TextDecoration.underline,
      ),
      recognizer: TapGestureRecognizer()
        ..onTap = () => Navigator.pushNamed(context, '/terms'),
    ),
  ),
)

// Highlighted text
Text.rich(
  context.i10n.marketing.promotion(
    highlight: (text) => TextSpan(
      text: text,
      style: TextStyle(
        color: AppColors.accent,
        fontWeight: FontWeight.bold,
      ),
    ),
  ),
)

Slang Configuration Template#

slang.yaml#

# Slang configuration file
base_locale: ko
fallback_strategy: base_locale

# Input settings
input_directory: lib/src/json
input_file_pattern: .i18n.json

# Output settings
# slang 4 writes translations.g.dart plus one file per locale
# (translations_ko.g.dart, translations_en.g.dart, ...).
# output_format was removed in slang 4.0.0.
output_directory: lib/src/translations
output_file_name: translations.g.dart

# Case settings
key_case: snake
key_map_case: snake
param_case: snake

# Other settings
string_interpolation: braces
flat_map: false
timestamp: true
statistics: true
translate_var: translations

# Interface generation (if needed)
interfaces:
  PageData:
    paths:
      - home
      - settings
      - profile

GPT Translation Hint Template#

JSON does not support inline comments, so translation hints for slang_gpt are provided via the reserved @ metadata keys (for example @app_name) rather than comments.

{
  "common": {
    "app_name": "Unibook",
    "@app_name": {
      "description": "App name - do not translate, keep as Unibook"
    }
  },
  "buttons": {
    "submit": "제출",
    "@submit": { "description": "Button text - keep short and clear (Submit)" },
    "confirm": "확인",
    "@confirm": { "description": "Button text - Confirm / OK" }
  },
  "pet": {
    "type(context=PetType)": {
      "dog": "강아지",
      "cat": "고양이"
    },
    "@type": {
      "description": "Pet species - maintain friendly tone; dog=dog, cat=cat"
    }
  }
}

검색어를 입력하면 문서를 찾습니다.

↑ ↓ 이동 · Enter 열기Esc 닫기