본문 바로가기

Projects/업무-무역

[VBA] 파파고 API를 활용한 워드 번역기

 

구현사례

워드파일 파파고 번역기


왜 만들었는가

 

종합상사에 왔더니 생가보다 번역할 일이 많이 생긴다. 특히 거래선이 일본 업체이고, 동경 거래소에 상장된 상장기업이다 보니 일본어로 된 자료가 정말 많다. 기업공시 내역, 실적자료, 사업보고서 등 상장기업의 자료는 쏟아지는데, 계속해서 현황을 업데이트하기 위해서는 자료를 번역하고 요약해서 부서 내부적으로 공유를  해주는 작업이 필요하다.

일본어를 구사할 수 있다는 이유만으로 번역 업무를 자주 맡게 되는데, 처음에는 직접 다 번역을 해보았다.
하지만 하면 할 수록 이걸 직접 번역하는건 너무 비효율적이라는 생각이 들었다.

읽어야 하는 자료는 너무 많은데, 시간과 인력은 부족하니 번역기에 의존할 수 밖에 없었고 파파고 번역기와 구글 번역기를 모두 써보았다.

파파고의 일 -> 한 번역은 놀라울 정도로 정확하고 어순도 자연스러웠다.
문장 단위로 잘만 끊어줘서 입력하면 매끄럽고 정확한 (휴먼 에러가 없는) 번역 결과물이 나왔다.

파파고 번역기를 써본 후에는 파파고 번역으로 초벌 번역을 한 후, 해당 내용에 이상이 없는지 검증하는 방식으로 작업 시간을 크게 단축시킬 수 있었다.

하지만 긴 문서의 경우 문장 하나 하나 파파고에 집어넣는 것도 일이었다.
(파파고를 써본 분들은 알겠지만 문서 전체를 통으로 넣으면 번역이 잘 안된다. 문장 단위로 쪼개서 넣어줘야 잘된다)

긴 문서를 번역하기 위해서 파파고 번역 API를 활용한 매크로를 만들었다.


프로젝트 개요

언어 : VBA

 

주요 패키지, 라이브러리

  • Papago API : Client ID 1개당 하루에 번역할 수 있는 문자 한도가 1만자다. 20~30페이지 되는 글은 기본 몇만자다. 1만자로는 별로 쓸모가 없어서, 계정 1개당 만들 수 있는 최대 Client ID 개수인 10개를 모두 만들고 활용
  • VBA-JSON (https://github.com/VBA-tools/VBA-JSON) 엑셀에서 JSON을 파싱할 수 있게 도와주는 라이브러리다. Papago API의 Response가 JSON이기 때문에  사용
  • Microsoft XML v6.0 : VBA에서 HTTP Request를 가능하게 해주는 대표적인 라이브러리. VBA 크롤링은 이 라이브러리를 필수적으로 사용
  • Microsoft Scripting Runtime : VBA는 자체적으로는 Dictionary (key:value로 이루어진 데이터 형태)를 다룰 수 없고, 이 라이브러리를 사용해야 Dictionary Object를 사용할 수 있다. VBA-JSON와 같이 사용하면 JSON을 VBA에서도 수월하게 파싱할 수 있다.
    ->10개의 키를 배열에 담아두고, 하나가 다  소진되면 다음 키를 사용하는 구조다.

작동 방식

  1. Word 문서에 있는 모든 문단(Paragraph)를 하나의 덩어리로 인식하고, 모든 문단에 대한 For Loop를 실행
  2. 파파고 API의 10개 Client ID는 Array에 담아두고, 번역을 하다가 ID 하나가 소진되면 다음 키로 진행
    (글자수 초과인 경우 리퀘스트 시 429 에러가 발생한다. 이 에러가 발생할 경우 그 다음 키로 넘어갈 수 있는 조건문을 삽입)



구현 코드

1. 사용 레퍼런스 : 아래 이미지 + VBA-JSON

2. 코드

 

Option Explicit
Sub get_trans()


'변수 정의
Dim JSON As Object
Dim paragraph As Word.paragraph
Dim myrange As Range

Dim para, myurl As String
Dim mytrans As String
Dim httpObject As Object
Dim i As Long


Dim client_id(9) As Variant
Dim client_secret(9) As Variant

client_id(0) = 
client_id(1) = 
client_id(2) = 
client_id(3) = 
client_id(4) = 
client_id(5) = 
client_id(6) = 
client_id(7) = 
client_id(8) = 
client_id(9) = 

client_secret(0) = 
client_secret(1) =
client_secret(2) = 
client_secret(3) = 
client_secret(4) = 
client_secret(5) = 
client_secret(6) = 
client_secret(7) = 
client_secret(8) = 
client_secret(9) = 




myurl = "https://openapi.naver.com/v1/papago/n2mt"
i = 0
For Each paragraph In ActiveDocument.Paragraphs
'각 단락을 input으로 넣기
    para = "source=ja&target=ko&text=" & paragraph.Range.Text
    Set httpObject = CreateObject("MSXML2.XMLHTTP")
    With httpObject
        .Open "POST", myurl, False
        .setRequestHeader "User-Agent", "curl/7.49.1"
        .setRequestHeader "Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"
        .setRequestHeader "X-Naver-Client-Id", client_id(i)
        .setRequestHeader "X-Naver-Client-Secret", client_secret(i)
        .send para
        Set JSON = JsonConverter.ParseJson(.responseText)
    End With
    
    '요청량 제한이 뜨면 429가 뜨기 때문에 일단 429 기준으로 구분
    If httpObject.Status <> 429 Then
        ' 성공했을 경우 번역 내용
        If httpObject.Status = 200 Then
            mytrans = JSON("message")("result")("translatedText")
            Set myrange = _
            ActiveDocument.Range(paragraph.Range.Start, _
            paragraph.Range.End - 1)
            ' End -1를 해주는 이유는 -1이 없으면 번역 내용이 새로운 단락에서 시작됨 -> For문 구동 시 에러
            ' 그 단락 다음에 shift enter(Chr(11)) 입력해주고 끼우기
            myrange.InsertAfter Chr(11) & mytrans & Chr(11)
        End If
    '10000자 다 썼을 경우 대처법
    Else
        i = i + 1
        Set httpObject = CreateObject("MSXML2.XMLHTTP")
        With httpObject
            .Open "POST", myurl, False
            .setRequestHeader "User-Agent", "curl/7.49.1"
            .setRequestHeader "Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"
            .setRequestHeader "X-Naver-Client-Id", client_id(i)
            .setRequestHeader "X-Naver-Client-Secret", client_secret(i)
            .send para
            Set JSON = JsonConverter.ParseJson(.responseText)
        End With
        mytrans = JSON("message")("result")("translatedText")
        Set myrange = _
        ActiveDocument.Range(paragraph.Range.Start, _
        paragraph.Range.End - 1)
        myrange.InsertAfter Chr(11) & mytrans & Chr(11)
    End If
Next

End Sub

 

Comments

  • VBA 에디터와 VS CODE 사이에는 비가역적인 관계가 존재한다. VBA에디터를 쓰다가 VS CODE를 쓰면 다시는 VBA에디터로 코딩하고 싶지 않다. 둘 다 사용해본 입장에서 VSCODE 의 압도적인 장점들을 설명해보면
    • VS CODE의 Jupyter Notebook 기능을 이용하면 내가 작성한 코드가 제대로 된 건지 바로 바로 확인하다. 유닛테스트에 대한 별다른 지식이나 경험이 없어도 신속하게 코드에 대한 피드백을 받을 수 있다.
    • VS CODE 는 내가 만든 변수가 다른 곳에서 쓰인 적이 있는지 확인을 시켜준다 (변수를 한번도 안썼으면 색이 연하게 표시되어 경고 메시지도 뜬다) 변수 오탈자로 인한 오류를 많이 방지할 수 있다.
    • 폴더 네비게이션, 터미널이 모두 한 창에 있는 것도 엄청난 장점이다... 다른 창을 열어볼 필요가 없다. (반면 VBA 에디터에서 코딩한 것은 엑셀 화면에서 다시 확인해봐야 하고, 별도 파일이랑 연동이 되어 있으면 폴더도 따로 열어야 한다...)
  • 그럼에도 불구하고 워드와 엑셀 제어를 위한 유일한 언어라는 그 독점적 지위 때문에 VBA를 쓰지 않을 수 없다...
  • 파파고 번역의 정확성을 높이기 위해서는 번역 단위를 잘 설정해 줘야 한다. 여러 문장을 한번에 번역하면 번역에 오류가 많이 생긴다. 문장이 짧으면 문장 단위로, 문장이 길면 의미 단위로 쪼개서 API의 data로 넣어줘야 한다. 이번 매크로에서는 번역이 되는 단위의 구분 기준이 'Enter 기호'다. 그래서 보다 정확한 번역이 필요할 경우 엔터를 쳐주면 된다.


기타

스스로 만들었음에도 불구하고 활용성은 그닥 높지 않다.

 

그 이유는
1) 대부분의 문서나 자료는 pdf형식인데, 이를 Word형식으로 가져오면 문서 양식이 깨진다.
2) 표, 그래프 등 다른 시각적 요소나 양식이 포함된 문서는 번역이 잘 되지 않는다.
3) 내가 번역하고자 하는 문장이나 덩어리 단위로 끊어주는 것도 일이다...


이 3가지 문제를 매우 훌륭하게 해결한 사례가 있는데.. 이는 다음 글에서 소개해보고자  한다.

그래도 처음으로 파파고 API와 Word VBA를 활용한 프로젝트였다는 점에서 의미가 있다고 본다.