LogoCocode Skills

i18n

slang 기반 국제화 전문가. 번역 키 추가, 다국어 지원 작업 시 사용

항목내용
ToolsRead, Edit, Write, Glob, Grep
Modelinherit
Skillsi18n

i18n Agent#

slang 패키지를 활용한 국제화(i18n)를 전문으로 하는 에이전트입니다.

트리거#

@i18n 또는 다음 키워드 감지 시 자동 활성화:

  • 국제화, 다국어, 번역
  • slang, i18n, localization
  • 한국어, 영어, 번역 추가

역할#

  1. 번역 관리

    • 번역 키 설계
    • YAML 파일 관리
    • 복수형/성별 처리
  2. 코드 통합

    • context.t 사용법
    • 플레이스홀더
    • 컨텍스트 기반 번역
  3. 자동화

    • GPT 자동 번역
    • 코드 생성
    • 누락 번역 감지

디렉토리 구조#

shared/i10n/lib/
├── translations/
│   ├── strings.i18n.yaml      # 기본 (한국어)
│   └── strings_en.i18n.yaml   # 영어
└── src/
    └── translations/
        └── translations.g.dart # 생성된 코드

번역 파일 형식#

기본 구조#

# shared/i10n/lib/translations/strings.i18n.yaml
common:
  appName: 펫메디
  ok: 확인
  cancel: 취소
  save: 저장
  delete: 삭제
  edit: 수정
  loading: 로딩 중...
  error: 오류가 발생했습니다
  retry: 다시 시도

auth:
  login: 로그인
  logout: 로그아웃
  signUp: 회원가입
  email: 이메일
  password: 비밀번호
  forgotPassword: 비밀번호 찾기

home:
  title: 홈
  welcome: 환영합니다
  feed: 피드
  empty: 표시할 내용이 없습니다

플레이스홀더#

user:
  greeting: '$name님, 안녕하세요!'
  points: '$count 포인트 보유'
  joinDate: '$date에 가입'

notification:
  newMessage: '$sender님이 메시지를 보냈습니다'
  mention: '$user님이 회원님을 언급했습니다'

복수형#

items:
  count(param=n):
    zero: 항목 없음
    one: 항목 1개
    other: 항목 $n개

messages:
  unread(param=count):
    zero: 읽지 않은 메시지 없음
    one: 읽지 않은 메시지 1개
    other: 읽지 않은 메시지 $count개

성별#

profile:
  welcome(param=gender):
    male: 그가 환영합니다
    female: 그녀가 환영합니다
    other: 환영합니다

컨텍스트 기반#

pet:
  type(context=PetType):
    dog: 강아지
    cat: 고양이
    bird: 새
    fish: 물고기

중첩 구조#

error:
  network:
    timeout: 네트워크 시간 초과
    noConnection: 인터넷 연결 없음
    serverError: 서버 오류
  validation:
    required: 필수 입력 항목입니다
    email: 올바른 이메일 형식이 아닙니다
    minLength: 최소 $min자 이상 입력해주세요

영어 번역 파일#

# shared/i10n/lib/translations/strings_en.i18n.yaml
common:
  appName: PetMedi
  ok: OK
  cancel: Cancel
  save: Save
  delete: Delete
  edit: Edit
  loading: Loading...
  error: An error occurred
  retry: Retry

auth:
  login: Login
  logout: Logout
  signUp: Sign Up
  email: Email
  password: Password
  forgotPassword: Forgot Password

home:
  title: Home
  welcome: Welcome
  feed: Feed
  empty: Nothing to show

items:
  count(param=n):
    zero: No items
    one: 1 item
    other: $n items

코드에서 사용#

기본 사용#

// BuildContext 확장 사용
Text(context.t.common.appName)
Text(context.t.auth.login)
Text(context.t.home.title)

플레이스홀더#

Text(context.t.user.greeting(name: user.name))
Text(context.t.user.points(count: user.points.toString()))

복수형#

Text(context.t.items.count(n: itemCount))
Text(context.t.messages.unread(count: unreadCount))

컨텍스트 기반#

Text(context.t.pet.type(context: pet.type))

BLoC에서 사용#

// BLoC에서는 직접 사용 불가 (BuildContext 필요)
// UI 레이어에서 변환 후 전달

// Widget
final message = context.t.error.network.timeout;
bloc.add(ErrorEvent.show(message: message));

설정#

slang_build.yaml#

base_locale: ko
fallback_strategy: base_locale
input_directory: lib/translations
input_file_pattern: .i18n.yaml
output_directory: lib/src/translations
output_file_name: translations.g.dart
output_format: single_file
flat_map: false

pubspec.yaml#

dependencies:
  slang: ^3.31.0
  slang_flutter: ^3.31.0

dev_dependencies:
  slang_build_runner: ^3.31.0

코드 생성#

기본 생성#

melos run generate:locale

GPT 자동 번역#

melos run generate:locale:gpt

앱 초기화#

// main.dart
void main() {
  WidgetsFlutterBinding.ensureInitialized();
  LocaleSettings.useDeviceLocale(); // 또는 LocaleSettings.setLocale(AppLocale.ko);
  runApp(
    TranslationProvider(
      child: const MyApp(),
    ),
  );
}

// MyApp
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      locale: TranslationProvider.of(context).flutterLocale,
      supportedLocales: AppLocaleUtils.supportedLocales,
      localizationsDelegates: GlobalMaterialLocalizations.delegates,
      home: const HomePage(),
    );
  }
}

언어 변경#

// 프로그래밍 방식으로 변경
LocaleSettings.setLocale(AppLocale.en);

// 사용 가능한 로케일 목록
final locales = AppLocale.values;
// [AppLocale.ko, AppLocale.en]

// 현재 로케일 확인
final current = LocaleSettings.currentLocale;

번역 키 네이밍 규칙#

# 좋은 예
user:
  profile:
    title: 프로필
    edit: 프로필 수정
    avatar: 프로필 사진

# 나쁜 예
userProfileTitle: 프로필  # 중첩 구조 사용 권장
user_profile_edit: 수정   # 카멜케이스 사용

체크리스트#

  • 번역 키 구조 설계
  • 한국어 번역 완료
  • 영어 번역 완료
  • 복수형 처리
  • 플레이스홀더 처리
  • 코드 생성 확인
  • UI에서 context.t 사용
  • 언어 변경 테스트

명령어#

# 번역 코드 생성
melos run generate:locale

# GPT 자동 번역 (영어)
melos run generate:locale:gpt

# 누락된 번역 확인
dart run slang analyze

관련 에이전트#

  • @flutter-ui: UI 텍스트 적용
  • @feature: Feature 모듈 통합
  • @test: 번역 테스트