LogoSkills

i18n-agent

Slang 기반 국제화 전문가입니다. 번역 키 추가와 다국어 지원 작업에 사용합니다.

/shared:i18n — 여러 나라 말로 번역해 주는 도우미#

항목내용
실행 명령/shared:i18n
별칭/i18n:add, /locale:create
모델sonnet
사용 도구 Read, Edit, Write, Glob, Grep
연계 스킬i18n

한마디로#

앱 화면에 나오는 모든 글자(버튼, 안내 문구 등)를 11개 나라 언어로 번역해 관리해 주는 도우미입니다. 식당 메뉴판을 여러 나라 말로 만들어 손님이 누구든 알아볼 수 있게 하는 것과 같아요.

누가·언제 쓰나요#

  • 앱에 새 화면이나 버튼을 추가했는데 여러 나라 사용자가 자기 언어로 봐야 할 때
  • 한국어로 쓴 문구를 영어·일본어·중국어 등 다른 언어로도 보이게 하고 싶을 때

/shared:i18n 명령을 부르면 이 도우미가 활성화됩니다. (같은 뜻으로 /i18n:add, /locale:create 로도 부를 수 있어요.)

무엇을 해주나요#

  • 번역할 문구마다 고유 이름표(번역 Key)를 붙여 정리해 줍니다.
  • 지원 언어는 총 11개입니다 — 아랍어(ar), 독일어(de), 영어(en), 스페인어(es), 프랑스어(fr), 이탈리아어(it), 일본어(ja), 한국어(ko), 포르투갈어(pt), 러시아어(ru), 중국어 간체(zh_Hans).
  • 단순한 문구뿐 아니라 "항목 1개 / 항목 5개"처럼 개수에 따라 달라지는 표현, 이름이 들어가는 문구("환영합니다, 홍길동님!"), 성별에 따라 달라지는 호칭까지 처리합니다.
  • 번역 내용은 언어별 JSON 파일(예: translations_ko.i18n.json)에 저장되고, 앱에서 실제로 쓰이는 코드(translations.g.dart)는 자동으로 만들어집니다.

어떻게 쓰나요#

번역 도우미는 아래와 같은 항목을 받아 일합니다.

key:       번역 이름표 (영문 snake_case, 필수)) home_title
value_ko:  한국어 번역 문구 (필수)) 홈
namespace: 어느 화면·영역의 문구인지 (선택)) home, auth
has_params: 이름·숫자 같은 값이 끼어드는지 여부 (선택)

번역 코드를 새로 만들거나 점검할 때는 아래 명령들을 씁니다.

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

# 번역 파일이 올바른지 점검
melos run translate:slang:fix

# 모든 언어 자동 번역 (AI 사용)
melos run translate:slang:all

안에서 무슨 일이 벌어지나요#

대략 이런 순서로 일이 진행됩니다.

  1. 먼저 영어(기본) 번역 파일과 한국어 번역 파일에 새 문구를 적습니다.
  2. 이름이 끼어드는 문구({param}), 개수에 따라 달라지는 문구(복수형) 등의 표기 규칙이 맞는지 확인합니다.
  3. 번역 설정 파일(slang.yaml)이 올바른지 점검합니다.
  4. melos run generate:locale 명령으로 앱이 실제로 사용할 번역 코드를 자동 생성합니다.
  5. 화면에서 context.i10n 방식으로 번역이 잘 불려 나오는지, 앱 최상단에 번역 공급기(TranslationProvider)가 자리잡았는지 확인합니다.

⚙️ 상세 옵션·실행 명세 (개발자 / AI 에이전트용)

Role#

Manages multi-language support system using Slang.

  • Translation key management
  • 11 language support (ar, de, en, es, fr, it, ja, ko, pt, ru, zh_Hans)
  • context.i10n extension method
  • Pluralization, gender, parameter handling

Activation Conditions#

  • /shared:i18n Activated when command is invoked
  • Invoked during translation and multi-language support work

Parameters#

ParameterRequiredDescription
keyTranslation Key (snake_case)
value_koKorean Translation Value
namespaceNamespace (예: home, auth)
has_paramsWhether parameters are included

Package Structure#

shared/i10n/
├── lib/
│   ├── i10n.dart                     # Export 파일
│   └── src/
│       ├── translations/
│       │   ├── translations.i18n.json      # default 번역 (영어)
│       │   ├── translations_ar.i18n.json   # 아랍어
│       │   ├── translations_de.i18n.json   # 독일어
│       │   ├── translations_es.i18n.json   # 스페인어
│       │   ├── translations_fr.i18n.json   # 프랑스어
│       │   ├── translations_it.i18n.json   # 이탈리아어
│       │   ├── translations_ja.i18n.json   # 일본어
│       │   ├── translations_ko.i18n.json   # 한국어
│       │   ├── translations_pt.i18n.json   # 포르투갈어
│       │   ├── translations_ru.i18n.json   # 러시아어
│       │   ├── translations_zh_Hans.i18n.json  # in progress국어 간체
│       │   └── translations.g.dart         # 자동 생성
│       └── utils/
│           └── translation_extension.dart  # context.i10n 확장
└── slang.yaml                              # Slang 설정

Import Order (Required)#

// 1. Flutter standard
import 'package:flutter/widgets.dart';

// 2. Slang package
import 'package:slang_flutter/slang_flutter.dart';

// 3. Generated translations
import '../translations/translations.g.dart';

Core Patterns#

1. Main Export File#

/// i10n 패키지 export
library i10n;

export 'package:flutter_localizations/flutter_localizations.dart';
export 'package:slang_flutter/slang_flutter.dart';
export 'src/translations/translations.g.dart';
export 'src/utils/translation_extension.dart';

2. context.i10n Extension Method#

import 'package:flutter/widgets.dart';

import '../translations/translations.g.dart';

/// BuildContext 번역 확장
extension TranslationExtension on BuildContext {
  /// 현재 로케일의 번역 객체 접근
  ///
  /// Usage example:
  /// ```dart
  /// Text(context.i10n.home.title)
  /// Text(context.i10n.common.confirm)
  /// <pre><code>  Translations get i10n =&gt; Translations.of(this);
}</code></pre>

### 3. Translation JSON Structure

<pre><code>// translations_ko.i18n.json (한국어)
{
  &quot;@@locale&quot;: &quot;ko&quot;,
  &quot;common&quot;: {
    &quot;confirm&quot;: &quot;확인&quot;,
    &quot;cancel&quot;: &quot;취소&quot;,
    &quot;save&quot;: &quot;저장&quot;,
    &quot;delete&quot;: &quot;삭제&quot;,
    &quot;edit&quot;: &quot;수정&quot;,
    &quot;close&quot;: &quot;닫기&quot;,
    &quot;loading&quot;: &quot;로딩 in progress...&quot;,
    &quot;error&quot;: &quot;오류가 발생했습니다&quot;,
    &quot;retry&quot;: &quot;다시 시도&quot;,
    &quot;search&quot;: &quot;검색&quot;,
    &quot;noData&quot;: &quot;데이터가 없습니다&quot;
  },
  &quot;auth&quot;: {
    &quot;login&quot;: &quot;로그인&quot;,
    &quot;logout&quot;: &quot;로그아웃&quot;,
    &quot;signUp&quot;: &quot;회원가입&quot;,
    &quot;email&quot;: &quot;이메일&quot;,
    &quot;password&quot;: &quot;비밀번호&quot;,
    &quot;forgotPassword&quot;: &quot;비밀번호 찾기&quot;
  },
  &quot;home&quot;: {
    &quot;title&quot;: &quot;&quot;,
    &quot;welcome&quot;: &quot;환영합니다, {name}!&quot;,
    &quot;itemCount(context=count)&quot;: {
      &quot;zero&quot;: &quot;항목이 없습니다&quot;,
      &quot;one&quot;: &quot;1개의 항목&quot;,
      &quot;other&quot;: &quot;{count}개의 항목&quot;
    }
  },
  &quot;error&quot;: {
    &quot;network&quot;: &quot;네트워크 연결을 확인해주세요&quot;,
    &quot;server&quot;: &quot;서버 오류가 발생했습니다&quot;,
    &quot;unknown&quot;: &quot;알 수 없는 오류가 발생했습니다&quot;,
    &quot;validation&quot;: {
      &quot;required&quot;: &quot;{field}() 필수입니다&quot;,
      &quot;email&quot;: &quot;올바른 이메일 형식이 아닙니다&quot;,
      &quot;minLength&quot;: &quot;{field}() 최소 {min}자 이상이어야 합니다&quot;
    }
  }
}</code></pre>

### 4. English Translation (Default)

<pre><code>// translations.i18n.json (영어 - default)
{
  &quot;@@locale&quot;: &quot;en&quot;,
  &quot;common&quot;: {
    &quot;confirm&quot;: &quot;Confirm&quot;,
    &quot;cancel&quot;: &quot;Cancel&quot;,
    &quot;save&quot;: &quot;Save&quot;,
    &quot;delete&quot;: &quot;Delete&quot;,
    &quot;edit&quot;: &quot;Edit&quot;,
    &quot;close&quot;: &quot;Close&quot;,
    &quot;loading&quot;: &quot;Loading...&quot;,
    &quot;error&quot;: &quot;An error occurred&quot;,
    &quot;retry&quot;: &quot;Retry&quot;,
    &quot;search&quot;: &quot;Search&quot;,
    &quot;noData&quot;: &quot;No data available&quot;
  },
  &quot;auth&quot;: {
    &quot;login&quot;: &quot;Login&quot;,
    &quot;logout&quot;: &quot;Logout&quot;,
    &quot;signUp&quot;: &quot;Sign Up&quot;,
    &quot;email&quot;: &quot;Email&quot;,
    &quot;password&quot;: &quot;Password&quot;,
    &quot;forgotPassword&quot;: &quot;Forgot Password&quot;
  },
  &quot;home&quot;: {
    &quot;title&quot;: &quot;Home&quot;,
    &quot;welcome&quot;: &quot;Welcome, {name}!&quot;,
    &quot;itemCount(context=count)&quot;: {
      &quot;zero&quot;: &quot;No items&quot;,
      &quot;one&quot;: &quot;1 item&quot;,
      &quot;other&quot;: &quot;{count} items&quot;
    }
  },
  &quot;error&quot;: {
    &quot;network&quot;: &quot;Please check your network connection&quot;,
    &quot;server&quot;: &quot;A server error occurred&quot;,
    &quot;unknown&quot;: &quot;An unknown error occurred&quot;,
    &quot;validation&quot;: {
      &quot;required&quot;: &quot;{field} is required&quot;,
      &quot;email&quot;: &quot;Invalid email format&quot;,
      &quot;minLength&quot;: &quot;{field} must be at least {min} characters&quot;
    }
  }
}</code></pre>

### 5. Slang Configuration File

<pre><code># slang.yaml
base_locale: en
fallback_strategy: base_locale
input_directory: lib/src/translations
input_file_pattern: .i18n.json
output_directory: lib/src/translations
output_file_name: translations.g.dart
output_format: single_file
key_case: camel
key_map_case: camel
param_case: camel
string_interpolation: braces
flat_map: false
timestamp: false
statistics: true
translation_class_visibility: public
key_class_visibility: public</code></pre>

### 6. Usage in Widget

```dart
import 'package:flutter/material.dart';
import 'package:i10n/i10n.dart';

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(context.i10n.home.title),
      ),
      body: Column(
        children: [
          // 단순 문자열
          Text(context.i10n.common.confirm),

          // 파라미터 포함
          Text(context.i10n.home.welcome(name: '홍길동')),

          // 복수형
          Text(context.i10n.home.itemCount(count: 5)),

          // in progress첩 키
          Text(context.i10n.error.validation.required(field: '이름')),
        ],
      ),
    );
  }
}

7. App Setup#

import 'package:flutter/material.dart';
import 'package:i10n/i10n.dart';

class MyApp extends StatelessWidget {
  const MyApp({super.key});

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

Translation Grammar#

Basic String#

{
   " greeting " :  " 안녕하세요 " 
 }

Usage: context.i10n.greeting

Parameters#

{
   " welcome " :  " 환영합니다, {name}님! " 
 }

Usage: context.i10n.welcome(name: '홍길동')

Plurals#

{
   " itemCount(context=count) " : {
     " zero " :  " 항목 없음 " ,
     " one " :  " 1개 항목 " ,
     " two " :  " 2개 항목 " ,
     " few " :  " {count}개 항목 " ,
     " many " :  " {count}개 항목 " ,
     " other " :  " {count}개 항목 " 
   }
}

Usage: context.i10n.itemCount(count: 5)

Gender#

{
   " greetPerson(context=gender) " : {
     " male " :  " {name}씨 " ,
     " female " :  " {name}님 " ,
     " other " :  " {name}님 " 
   }
}

Usage: context.i10n.greetPerson(gender: Gender.female, name: '김영희')

Nested Keys#

{
   " error " : {
     " validation " : {
       " required " :  " {field}은(는) 필수입니다 " 
     }
  }
}

Usage: context.i10n.error.validation.required(field: '이메일')


Build Commands#

# Generate translation code
melos run generate:locale

# Verify translation files
melos run translate:slang:fix

# Translate all languages (using AI)
melos run translate:slang:all

# Build specific package only
cd shared/i10n  & &   dart run build_runner build --delete-conflicting-outputs

Reference Files#

shared/i10n/lib/i10n.dart
shared/i10n/lib/src/utils/translation_extension.dart
shared/i10n/lib/src/translations/translations_ko.i18n.json
shared/i10n/slang.yaml

Checklist#

  • Write translations.i18n.json (English) default translation
  • Write translations_ko.i18n.json (Korean) translation
  • Verify parameter syntax {param} is correct
  • Verify plural context=count syntax
  • Verify slang.yaml configuration
  • Execute melos run generate:locale
  • Verify context.i10n extension method usage
  • Place TranslationProvider at app root