Model Context Protocol server for Lokalise integration
npm install @channel.io/lokalise-mcpChannel 팀을 위한 Lokalise MCP 도구입니다. 이 도구는 Cursor에서 번역 키 생성 및 관리를 도와주는 AI 도구입니다.
Cursor에서 MCP로 사용하려면 .cursor/mcp.json 파일에 다음과 같이 설정합니다:
``json`
{
"mcpServers": {
"lokalise-mcp": {
"command": "npx -y @channel.io/lokalise-mcp",
"env": {
"LOKALISE_TOKEN": "your-lokalise-token",
"PROJECT_ID": "your-project-id",
"PLATFORMS": ["web", "ios", "android"]
}
}
}
}
- LOKALISE_TOKEN: Lokalise API에 접근하기 위한 개인 액세스 토큰입니다. Lokalise 계정 설정에서 발급받을 수 있습니다.
- PROJECT_ID: 작업할 Lokalise 프로젝트의 고유 식별자입니다. Lokalise 프로젝트 URL이나 설정에서 확인할 수 있습니다.
- PLATFORMS: 번역 키가 지원할 플랫폼 목록입니다.
이 MCP 서버는 두 가지 주요 기능을 제공합니다:
1. 번역 키 조회: 프로젝트에 이미 존재하는 번역 키를 검색합니다
2. 번역 키 생성: 새로운 번역 키를 생성하고 초기 번역값을 설정합니다
아래의 프롬프트를 사용하면 효과적으로 번역 키 추가 작업을 진행할 수 있습니다:
> 이 프롬프트는 ch-desk-web에서 사용하는 프롬프트입니다. 다른 프로젝트에서 사용하려면 프롬프트를 일부 수정해야 할 수 있습니다.
``
당신은 cursor 내에 통합된 LLM 에이전트입니다. 하드코딩된 한글 문자열에 대한 번역 키 추가 작업을 자동화하기 위해 아래 가이드라인을 준수하세요.
형식으로 번역 키:값 목록 준비 (value는 원본 한글)
- [!IMPORTANT] 특수 요소 처리:
* 템플릿 리터럴(${}) → import { sprintf } from 'sprintf-js'에서 parse할 수 있는 형식으로 변환 (e.g. "${name}님 안녕하세요" → "%s님 안녕하세요")
* HTML 태그 → 번역 값에 직접 innerHTML로 처리 (e.g. 제 이름은 라온입니다.)
* 줄바꿈 등 특수 문자 → 적절히 이스케이프 시퀀스 활용$3
- 동일한 번역 값(value)을 가진 키가 있는지 확인
- [!IMPORTANT] 리포지토리 루트에 있는 l10n/ko.json 파일에서 batch로 grep 하여 추출
- 중복이 없다면 최종 번역 키:값 목록 준비 후 다음 단계로 넘어감
- 중복 발견 시 옵션 제안:
* 기존 키 재사용 (도메인 로직이 아니라 일반적인 번역 키인 경우)
* 새 키 생성 (도메인 의존적인 번역 키인 경우)
- [!CRITICAL] 옵션에 대한 제안은 하되, 최종 결정은 사용자에게 물어볼 것 (/completion)
- 가독성 있게 코드블록(json)으로 제안할 것
- 사용자의 답변을 바탕으로 최종 { "key": "value" } 형식의 번역 키:값 목록 준비$3
- "작업 범위" 내 놓친 번역 키가 있는지 확인
- 이전 단계가 모두 정상적으로 수행되었는지 확인$3
- lokalise_get_keys 도구로 번역키 중복 확인
- [!CRITICAL] 중복 키가 있는 경우:
* 키에 version postfix를 붙여 중복 회피 (e.g. meet.meet_banner.title → meet.meet_banner.title.v1)
* 사용자에게 다시 최종 결정을 물어볼 것 (/completion)
- lokalise_create_keys 도구로 키 생성
- [!CRITICAL] 사용자에게 번역 키 태그를 한번도 받지 못한 경우 사용자에게 직접 요청할 것 (/completion)
- yarn download-l10n 스크립트 실행하여 번역 파일 갱신
- 코드 적용:
* import useTranslator from 'Hooks/useTranslator' 훅을 사용한 번역 키 적용
* 기본적으로 translate 함수를 사용
* 템플릿 변수 처리해야하는 경우, 함수의 파라미터를 적절히 사용
* innerHTML 처리해야하는 경우, translate 대신 translateWithInnerHtml 함수를 사용
번역 키:값 예시
$3
`json
{
"channel_settings.manage_webhooks.webhook_list.empty": "Webhook이 없습니다. 새 Webhook을 만들어 주세요."
"channel_settings.manage_webhooks.show_webhook.modal.title": "새 Webhook이 만들어졌습니다."
"channel_settings.manage_webhooks.show_webhook.modal.ok": "확인"
"channel_settings.manage_webhooks.edit_webhook.modal.title": "Webhook 관리"
"channel_settings.manage_webhooks.delete_webhook.success": "Webhook이 삭제되었습니다."
"channel_settings.plugin_setting.button_customize": "버튼 커스터마이징"
"channel_settings.plugin_setting.button_customize.reset": "초기화"
"channel_settings.integrations.messengers.line.apply_modal.locale": "언어"
"channel_settings.integrations.messengers.line.apply_modal.locale.description": "선택하신 언어에 따라 고객에게 부재중 메시지와 같은 자동 메시지가 전송됩니다."
"channel_settings.integrations.messengers.line.apply_modal.channel_id": "라인 Channel ID"
"channel_settings.integrations.messengers.line.apply_modal.channel_id.placeholder": "라인 Channel ID 입력"
"channel_settings.integrations.messengers.line.apply_modal.channel_secret": "라인 Channel Secret"
"channel_settings.integrations.messengers.line.apply_modal.channel_secret.placeholder": "라인 Channel Secret 입력"
"channel_settings.integrations.messengers.line.apply_modal.access_token": "Access token\n(long-lived)"
"channel_settings.integrations.messengers.line.apply_modal.access_token.placeholder": "Access token 입력"
"channel_settings.integrations.messengers.line.apply_modal.id": "Basic ID (또는 Premium ID)"
"channel_settings.integrations.messengers.line.apply_modal.id.placeholder": "Basic ID 또는 Premium ID를 입력"
"channel_settings.integrations.messengers.line.webhook_link_modal.description": "아래 링크를 복사하여 라인 Channel의 Messaging API settings - Webhook URL에 입력하고 Webhook을 활성화하면 연동이 완료됩니다."
}
`$3
`json
{
"common.cancel": "취소"
"common.confirm": "확인"
"common.close": "닫기"
"common.delete": "삭제"
"common.save": "저장"
"common.copy": "복사"
"common.apply": "적용"
"common.me": "나"
"common.next": "다음"
"common.retry": "재시도"
"common.time": "시간"
"common.no_data": "표시할 내용이 없습니다."
"common.not_empty": "비워둘 수 없습니다"
}
`$3
`json
{
"error.do_not_empty": "비워둘 수 없습니다."
"error.max_length": "%s자까지 입력할 수 있습니다."
"error.available_english_number": "영문, 숫자, -, _만 사용할 수 있습니다."
"error.aspect_ratio": "가로:세로 비율이 %s이 아닌 경우 등록할 수 없습니다."
"error.min_width": "가로 %spx 이하일 경우 등록할 수 없습니다."
"error.max_file_size": "최대 %s까지 등록할 수 있습니다."
"error.content_type": "%s만 등록할 수 있습니다."
"error.require_version_update.title": "앗, 이전 버전의 앱을 사용 중이에요"
"error.unsupported_file_extension": "파일 형식을 다시 확인해주세요."
"error.invalid_url": "잘못된 주소입니다."
}
`$3
`json
{
"log_message.create_chat": "%(subject)s<\/b>님이 %(object)s<\/b>(을)를 만들었습니다."
"log_message.invite_chat": "%(subject)s<\/b>님이 %(object)s<\/b>을(를) 초대했습니다."
"common.powered_by": "채널톡<\/b> 이용중"
"channel.invite_recommend_description": "현재 채널에 %s명<\/b>의 매니저가 있습니다. 매니저를 추가해도 추가 과금이 없으니<\/b> 안심하고 매니저를 초대하여 대화해보세요."
"campaign_editor.ui.operating_panel.activated_description": "언제, 어떻게 메시지를 전송할지 설정합니다. '운영' 설정을 끝으로 메시지가 전송됩니다.
\n예) 서울 접속자 중 가입하고 2주 동안 구매가 없으면 매주 월요일 아침 9시에<\/u><\/b> 전송",
"campaign_editor.ui.delay_panel.activated_description": "아래 '대기 시간' 만큼 기다렸다가 다시 대상 고객을 체크하고 '운영' 단계로 넘어갑니다.
\n예) 서울 접속자 중 가입하고 2주 동안<\/u><\/b> 구매가 없으면 매주 월요일 아침 9시에 전송"
}
`$3
`json
{
"chat_action.manager_list.header": "%s명 참여"
"confirm_delete_member": "%s님을 채널에서 삭제하시겠습니까?"
"invitation.sns.message": "%s님이 '%s' 채널로 당신을 초대했습니다.\n채널에 참여해 주시기 바랍니다."
"settings.billing.order_histories.discount_tooltip": "%s%% 할인 쿠폰 적용됨"
"support_bot.max": "최대 %s개까지 추가할 수 있습니다."
"bot.select.create_new_bot": "'%s' 새로 만들기..."
"teamchats.participants_list.title": "참여자 ∙ %s"
"expressive_query.values.format.plural": "%s 또는 %s개"
"common.append_new_value": "'%s' 입력"
"marketing.otm.success_modal.title_content": "%s명에게 메시지를 성공적으로 전달했습니다!👏"
"user_profile_page.menu.copy_link.tooltip": "유저 링크 복사\n%s"
"log_message.invite_chat": "%(subject)s<\/b>님이 %(object)s<\/b>을(를) 초대했습니다."
"log_message.leave_chat": "%(subject)s<\/b>님이 대화를 떠났습니다."
"log_message.change_chat_name": "%(subject)s<\/b>님이 그룹이름을 %(object)s<\/b>(으)로 변경하였습니다."
"notification.upload_file.description": "%(name)s 님이 파일을 업로드했습니다."
"log_message.remove": "%(subject)s<\/b>님이 상담을 삭제하였습니다."
"log_message.close": "%(subject)s<\/b>님이 상담을 종료하였습니다."
"log_message.unhold": "%(subject)s<\/b>님이 상담을 보류 해제 하였습니다."
}
````