Google Cloud Translate V2 을 활용해서 strings.xml 을 번역해 보겠습니다.
배경 설명
다국적(?) 앱을 만들어 볼 요량으로 여러버 시도했던 이야기를 다시 해 보겠습니다. 이제 우리앱은 다양한 언어를 구현하는 앱으로 발전하게 될 것 입니다.
우리가 작성하는 앱이 이렇게 구현이 된다면 어떤 느낌이 들까요 ??? 기본적으로 앱을 구현할 떄 영어 버전과 우리말 버전은 잘 만들어 집니다. 하지만, 다른 언어를 활용하는 앱을 구현 하는 것 다른 이야기 이지 않을 까 합니다.
이제 만들어진 한국어 버전의 strings.xml 을 보겠습니다.
<resources>
<string name="app_name">취업 검색, 다국어 지원</string>
<string name="todayTitle">일자리 리스트</string>
<string name="msgToday">구직자분들은 원하시는 공고를 클릭해서 자세한 정보를 확인해주시기 바랍니다.</string>
<string name="workInfo">작업\n정보</string>
<string name="workPlace">직장\n장소</string>
<string name="title_activity_google_login">구글 로그인</string>
<string name="doRegister">등록 ?</string>
<string name="doLogout">로그아웃</string>
<string name="mesgRegistorOnlyGoogle">이 앱의 사용자는 Google 계정만 등록합니다.</string>
<string name="addChatRoom">채팅방 만들기 ?</string>
<string name="titleChatRoom">채팅방</string>
<string name="titleMakeChatRoom">채팅방 만들기</string>
<string name="mesgMakeChatRoom">채팅방을 만드시겠습니까?</string>
<string name="OK">확인</string>
<string name="CANCEL">취소</string>
<string name="TITLE">제목</string>
<string name="ROOMNAME">방이름</string>
<string name="ROOMNO">방 번호</string>
<string name="entryRoomNm">방 이름 입력</string>
<string name="entryTitle">제목을 입력하세요</string>
<string name="saveCompleted">저장 완료</string>
<string name="title_activity_setting">환경</string>
<string name="title_translate_ty">언어 번역</string>
<string name="msgAutoTranslate">자동 번역</string>
<string name="msgTranslateNo">번역된 언어가 보이지 않습니다</string>
<string name="title_master_language">당신의 언어?</string>
<string name="localTime">현지 시간</string>
<string name="msgNonOwner">당신은 이 방을 만든 사용자가 아닙니다.</string>
<string name="msgGuestExists">이 방에는 채팅을 하는 사용자가 있습니다.</string>
<string name="msgLogOutClickAgain">로그아웃하시겠습니까?</string>
<string name="msgDontGetPicutre">사진을 얻지 마세요</string>
<string name="profileImage">사용자정보</string>
--- 중략 ---
<string name="longClickToMoveMarker">지정할 위치를 길게 클릭하세요</string>
<string name="msgNotFoundAddress">주소를 찾을 수 없습니다.</string>
<string name="msgReadyUpdate">이 앱의 새로운 기능 사용을 위한 새로운 버전이 확인 되었습니다. 새 버전을 사용할까요?</string>
<string name="msgUpdateCompleted">새로운 버전을 사용할 준비가 완료 되었습니다. 앱을 다시 시작 하세요.새로운 버전을 사용할 준비가 완료 되었습니다. 앱을 다시 시작 하세요.</string>
<string name="msgRequestPasswordEtc">채팅방 비밀번호 요청을 진행할까요???</string>
<string name="readyDate">업무개시가능일자 : %s</string>
<string name="sendChatReq">대화참여요청</string>
<string name="RequestJoinChat">채팅방 참여 요청</string>
<string name="msgRequestJoinChat">이 사용자 에게 채팅방 참여를 요청 할까요?</string>
<string name="msgBeforeSaveProfile">먼저 사용자 정보를 저장해야 합니다.</string>
<string name="menuReqList">비밀번호요청목록</string>
<string name="arrowBack">뒤로가기</string>
<string name="Save">저장</string>
<string name="baseAddress">기본주소: %s</string>
</resources>
영어버전의 strings.xml 에는 영어로 등록 합니다. android studio 에서 다국어 버전을 만들기 위해서 한국어 부터 추가해 등록 합니다.
추가(+)을 클릭하고 추가 하고자 하는 언어을 선택 하면 됩니다. 그러면 기본적인 폴더들이 생성이 될 것 같습니다.
번역기 구현해 보기
코드 구현은 python 으로 해 보겠습니다. 그래야 PC 에서 활용하기 수월 하기도 하고 이런 저런 추가 작업이 필요한 경우 원할하게 해 볼 수 있습니다.
from google.cloud import translate_v2 as translate
import os
import html
import requests
locale=["ko","us","ja","zh","vi","in","ar","bn","de","es","fr","hi","it","ms","nl","pt","ru","th","tr"]
gcLocale=["ko","en","ja","zh","vi","id","ar","bn","de","es","fr","hi","it","ms","nl","pt","ru","th","tr"]
target=["ko-rKR","","ja-rJP","zh-rCN","vi-rVN","in-rID","ar-rAE","bn-rIN","de-rDE","es-rES","fr-rFR","hi-rIN","it-rIT","ms-rMY","nl-rNL","pt-rPT","ru-rRU","th-rTH","tr-rTR"]
# 서비스 계정 키 파일 경로 설정 (다운로드한 JSON 파일 경로)
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = './multichat-a2026-a5e95fece213.json'
def translate_text(target: str, text: str):
"""Translates text into the target language.
Target must be an ISO 639-1 language code.
See https://g.co/cloud/translate/v2/translate-reference#supported_languages
"""
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
translate_client = translate.Client()
text = text.replace('\n','')
if isinstance(text, bytes):
text = text.decode("utf-8")
# Text can also be a sequence of strings, in which case this method
# will return a sequence of results for each text.
result = translate_client.translate(text, target_language=target)
# print("Text: {}".format(result["input"]))
# print("Translation: {}".format(result["translatedText"]))
# print("Detected source language: {}".format(result["detectedSourceLanguage"]))
rValue = result["translatedText"]
rValue = html.escape(rValue)
print('trans:', rValue)
return rValue
srcDir='C:/Users/nari4/AndroidStudioProjects/multichat416_v2/app/src/main/res'
tarDir='C:/Users/nari4/AndroidStudioProjects/multichat416_v2/images/res'
for loc in locale:
if loc == 'ko': continue
if loc == 'us': continue
print(locale.index(loc), gcLocale[locale.index(loc)], target[locale.index(loc)])
f=open(os.path.join(srcDir, 'values-ko-rKR/strings.xml'), 'r', encoding='UTF-8')
if os.path.isdir(os.path.join(tarDir, 'values-' + target[locale.index(loc)])):
pass
else:
os.mkdir(os.path.join(tarDir, 'values-' + target[locale.index(loc)]))
wf=open(os.path.join(tarDir, 'values-'+target[locale.index(loc)],'strings.xml'), 'w', encoding='UTF-8')
multiLineTy = False
passTy=False
sTitle=''
while True:
line = f.readline()
if not line: break
if '<string' in line and '</string' in line and '<![CDATA' not in line:
print(line.split('"')[1], line.split('<')[1].split('<')[0].split('>')[1])
wf.write('<string name="{0}">{1}</string>\n'.format(line.split('"')[1], translate_text(gcLocale[locale.index(loc)], line.split('<')[1].split('<')[0].split('>')[1])))
elif '<string' in line and '</string' in line and '<![CDATA' in line:
print(line.split('"')[1], line.split('<![CDATA[')[1].split(']]')[0])
wf.write('<string name="{0}">{1}</string>\n'.format(line.split('"')[1], translate_text(gcLocale[locale.index(loc)], line.split('<![CDATA[')[1].split(']]')[0])))
elif 'translatable="false' in line and '<string' in line and '</string' not in line:
passTy=True
elif '<string' in line and '</string' not in line:
multiLineTy = True
sTitle=line.split('"')[1]
print(line.split('"')[1], line.split('>')[1])
wf.write('<string name="{0}">{1}\n'.format(line.split('"')[1], translate_text(gcLocale[locale.index(loc)], line.split('>')[1])))
elif multiLineTy and '<string' not in line and '</string' not in line:
print(line)
wf.write('{0}\n'.format(translate_text(gcLocale[locale.index(loc)], line)))
elif multiLineTy and '<string' not in line and '</string' in line:
multiLineTy = False
wf.write('</string>\n')
elif passTy and '</string' in line:
passTy=False
elif passTy:
pass
elif 'translatable="false' in line:
pass
else:
if line != '':
print(line)
wf.write(line+'\n')
f.close()
wf.close()
print(loc, '------------------------- End Next...')
print('End All Job...')
위 코드는 한국어 버전의 strings.xml 을 기반으로 다른 언어 버전으로 번역을 자동화 하기 위한 python 코드 입니다.
strings.xml 의 구조는 resouces 태그 사이에 string 태크들이 들어 있는 구조을 가지고 있습니다.
물론 string 태크 사이에는 한줄에 끝나는 것도 있지만, 여러줄에 나누어져 있는 것도 있습니다. 그것들을 활요하기 위해서 코드 구현을 해 보았습니다.
source 을 보면
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = './multichat-a2026-a5e95fece213.json'
google service key 가 들어 있는 파일을 가지고 있어야 합니다. 이 것을 얻기 위해서는 firebase 에서 프로젝트을 생성하고 프로젝트 정보에서 서비스 키을 받아올 수 있어야 합니다.
여기서 생성되는 파일 이름이 길게 생성 되어 수정을 조금 했습니다. 키 생성이 되면 json 파일을 받을 수 있으니 그걸 받아 python 프로젝트 폴더에 같이 넣으시고 이름을 수정해 python source 코드에 추가해 주시면 됩니다.
그럼 실행 보겠습니다. 선언된 locale 순으로 자동 스럽게 번환이 될 것 입니다.
이렇게 변환된 파일을 이제 android project 에 적용해 보겠습니다.
android studio 에서 번역이 완료 되었는 지를 먼저 확인해 보았습니다. 외국어를 다 알지 못하는 입장(?)에서는 정상적으로 번역이 된 것 처럼 보입니다. 이제 빌드를 해 보겠습니다.
오류 메시지를 보면 번역시 오류가 발생한 strings.xml 을 찾아가 보면 아래 그림 처럼 string 값이 포함될 수 없는 값이 들어 있는 것을 확인해 볼 수 있습니다. 그걸 이제 하나 하나 수정을 해 주어야 합니다.
이렇게 수정이 완료된 이후 앱을 실행 하면서 하나씩 구동해 보았습니다.
앱은 분명 한개 구성을 하였습니다 . 여러 나라 언어로 선택 활용할 수 있습니다. 이제 다국적 앱이 시작 됩니다.
언제든 궁금한 부분이 있으시면 질문해 주시면 답변 달아 드리겠습니다.
'모바일 앱(안드로이드)' 카테고리의 다른 글
Jetpack Compose에서 알림 권한 요청과 알림 표시하기 (2) | 2025.02.03 |
---|---|
Jetpack Compose를 사용하여 AdMob 배너 광고 추가하기 (0) | 2025.02.01 |
Android Studio를 사용하여 Google Maps 연동 앱 만들기 (1) | 2025.01.30 |
Jetpack Compose 에서 dialog을 이용해 비밀번호 입력 화면 구성해 보기 (0) | 2025.01.27 |
Android studio 의 AVD의 화면은 왜 블랙 스크린이 되는 걸까 ? (3) | 2025.01.22 |