AI 번역에서 같은 용어가 다르게 나올 때 정리하는 방법

AI 번역에서 같은 한국어 단어가 서로 다른 영어로 나왔다면, 무조건 하나로 바꾸기 전에 문장의 분야를 확인하세요. 같은 단어라도 어떤 업무에서 쓰는지에 따라 다른 번역이 맞을 수 있습니다.

먼저 이번 번역에 사용할 용어집의 원본 파일과 버전을 정하고, 원문 단어와 분야, 사용할 영어 표현을 함께 적습니다. 이 글에서는 가상 용어와 문장을 예로 들어 바꿔야 할 표현과 그대로 둘 표현을 구분합니다.

아래 용어집과 비교 문장은 가상 예제입니다. Python 3.12.14로 합성 자료를 로컬에서 실행했습니다. 용어집 검사와 문장 전체의 뜻 확인은 따로 필요합니다.

가상승인원본terms-v2의 분야별8행을 대조하고 키와배치의 다의어정상사례와 버전불일치·같은분야승인충돌·미승인추가·누락4오류를 나눈 설명용 도해
한국어6용어·분야별승인8행·합성문장8개를 검사한다. auth/키=access key와catalog/키=item key,pipeline/배치=batch와ui/배치=layout은 정상이다. 같은auth/키에credential key추가,terms-v1버전,ui/빠른승인미승인추가,infra/작업큐누락은보류한다. 용어집이준비된후S03/S05/S08문장불일치를대조하며 실제번역서비스호출0회.

한국어 표기와 분야를 한 쌍으로 관리하기

Google Cloud 용어집 안내는 분야별 용어를 일관되게 번역하는 사전을 설명하고, 여러 뜻이 있는 단어에 문맥에 맞는 번역을 지정하는 예를 제시합니다. 같은 문서는 용어집 리소스의 버전 관리가 지원되지 않으므로 원본 파일을 보존할 것을 안내합니다. 이 글에서는 이 원칙을 로컬 버전 기록에 적용합니다. 실제 Google 용어집을 만들거나 서비스 동작을 시험한 내용은 아닙니다.

W3C ITS 2.0의 Domain·Terminology 설명은 내용의 주제·분야 정보를 용어 선택에 사용할 수 있고 용어에 정의 등의 정보를 연결할 수 있음을 설명합니다. 아래 product·auth 같은 분류명과 승인 정책은 이 예제에서 정한 값입니다. ITS 표준 파일을 구현한 코드는 아닙니다.

원본은 terms-v2로 고정합니다. 승인란의 true는 검증용 가상 값이며 실제 담당자의 결재를 대신하지 않습니다. 루미보드와 모든 용어·문장은 설명을 위해 만든 자료입니다.

분야 한국어 용어 terms-v2 승인 번역 의미 범위
product 루미보드 LumiBoard 가상 제품 이름, 대소문자 유지
auth 키 access key 접근 인증에 쓰는 키
catalog 키 item key 품목을 식별하는 키
pipeline 배치 batch 묶어서 처리하는 작업
ui 배치 layout 화면 요소의 배치
software 릴리스 release 소프트웨어 릴리스
support 티켓 ticket 지원 요청 기록
infra 작업큐 work queue 작업 대기열

한국어 표기 종류는 루미보드·키·배치·릴리스·티켓·작업큐의 6개입니다. 키와 배치는 각각 두 분야에 있으므로 승인 행은 8개입니다. auth/키와 catalog/키가 서로 다른 영어인 것은 이 계약에서 정상입니다. 같은 auth/키에 access key와 credential key를 동시에 승인하면 충돌입니다.

원문 여덟 문장을 그대로 보관하기

분야는 검토자가 원문 맥락을 보고 미리 표시한 것입니다. 코드가 문장을 이해해서 분야를 자동 추론하지 않습니다. 분야를 확정할 수 없는 원문은 용어 통일 전에 보류해야 합니다.

ID 분야 가상 한국어 원문 승인 용어가 들어간 비교 문장
S01 product 루미보드 버튼을 연다. Open the LumiBoard button.
S02 auth 키를 교체한다. Rotate the access key.
S03 catalog 키를 기준으로 품목을 찾는다. Find the item by the item key.
S04 pipeline 배치를 실행한다. Run the batch.
S05 ui 배치를 바꾼다. Change the layout.
S06 software 릴리스를 기록한다. Record the release.
S07 support 티켓을 연결한다. Link the ticket.
S08 infra 작업큐를 비운다. Clear the work queue.

오른쪽 문장도 사람이 작성한 합성 비교문입니다. 문장 전체의 번역 정답이나 특정 모델의 번역 품질 점수가 아닙니다. 이번 코드가 검사하는 것은 표시된 분야의 승인 용어가 대소문자와 단어 경계를 지켜 들어갔는지입니다. 동사·관사·문장 자연스러움은 별도로 검토합니다.

번역을 고치기 전에 용어집의 네 오류를 분리하기

오류 용어집은 원본 사본에서 작업큐 행을 빼고 auth/키의 두 번째 승인값을 추가한 것입니다. 또 ui/빠른승인 → fast approval을 미승인 상태로 넣고 버전명을 terms-v1로 적었습니다. 빠른승인은 미승인 추가 반례로만 존재하며 여섯 원본 용어에 합치지 않습니다.

충돌 대장 항목 관측한 오류 해결 근거 처리
버전 terms-v1을 사용 지정 원본 terms-v2 승인 원본 파일과 버전을 다시 연결
같은 분야의 승인 충돌 auth/키에 승인 번역 2개 terms-v2의 access key 사본의 credential key 추가를 보류
미승인 추가 ui/빠른승인 행 승인 false 원본에 해당 항목 없음 별도 제안 대장으로 옮기고 번역에 반영하지 않음
승인 항목 누락 infra/작업큐 행 없음 원본의 work queue 승인 원본에서 복구하고 사유 기록

번역 결과를 용어집에 맞추려다가 용어집 자체의 충돌을 숨기지 않습니다. 같은 키의 승인값 두 개 중 하나를 AI가 임의로 고르거나, 누락을 기억으로 채우는 처리도 이번 완료 조건에 맞지 않습니다. 해결 담당자는 실제 업무에서 정할 사람이며 이 실습에는 실제 승인자가 없습니다.

전체 검증 코드를 복사해 실행하기

다음을 check_glossary.py로 저장하고 python check_glossary.py를 실행합니다. 여섯 용어, 여덟 승인 행, 여덟 원문과 정상·오류 사본이 전부 코드 안에 있습니다. 별도 첨부나 온라인 번역 계정이 필요 없습니다.

"""Six fictional Korean terms, eight domain entries, eight synthetic sentences."""
import copy
import re
from collections import defaultdict

VERSION = 'terms-v2'
BASE = [
    ('product', '루미보드', 'LumiBoard', True),
    ('auth', '키', 'access key', True),
    ('catalog', '키', 'item key', True),
    ('pipeline', '배치', 'batch', True),
    ('ui', '배치', 'layout', True),
    ('software', '릴리스', 'release', True),
    ('support', '티켓', 'ticket', True),
    ('infra', '작업큐', 'work queue', True),
]
SOURCE = [
    ('S01', 'product', '루미보드', '루미보드 버튼을 연다.'),
    ('S02', 'auth', '키', '키를 교체한다.'),
    ('S03', 'catalog', '키', '키를 기준으로 품목을 찾는다.'),
    ('S04', 'pipeline', '배치', '배치를 실행한다.'),
    ('S05', 'ui', '배치', '배치를 바꾼다.'),
    ('S06', 'software', '릴리스', '릴리스를 기록한다.'),
    ('S07', 'support', '티켓', '티켓을 연결한다.'),
    ('S08', 'infra', '작업큐', '작업큐를 비운다.'),
]
GOOD = [
    {'id': 'S01', 'text': 'Open the LumiBoard button.'},
    {'id': 'S02', 'text': 'Rotate the access key.'},
    {'id': 'S03', 'text': 'Find the item by the item key.'},
    {'id': 'S04', 'text': 'Run the batch.'},
    {'id': 'S05', 'text': 'Change the layout.'},
    {'id': 'S06', 'text': 'Record the release.'},
    {'id': 'S07', 'text': 'Link the ticket.'},
    {'id': 'S08', 'text': 'Clear the work queue.'},
]

def audit_glossary(version, rows):
    errors = []
    if version != VERSION:
        errors.append('VERSION_MISMATCH')
    expected = {(domain, term): target for domain, term, target, ok in BASE}
    approved = defaultdict(set)
    for domain, term, target, ok in rows:
        key = (domain, term)
        label = domain + '/' + term
        if ok is not True:
            errors.append('UNAPPROVED_ADDITION:' + label)
        else:
            approved[key].add(target)
            if key not in expected:
                errors.append('UNAPPROVED_ADDITION:' + label)
    for key in sorted(approved):
        label = '/'.join(key)
        if len(approved[key]) > 1:
            errors.append('APPROVED_COLLISION:' + label)
        elif key in expected and approved[key] != {expected[key]}:
            errors.append('APPROVED_VALUE_MISMATCH:' + label)
    for key in sorted(expected):
        if key not in approved:
            errors.append('MISSING_APPROVED_GLOSSARY:' + '/'.join(key))
    return sorted(set(errors))

def audit_sentences(source, draft, rows):
    if audit_glossary(VERSION, rows):
        return ['GLOSSARY_NOT_READY']
    expected_ids = [row[0] for row in source]
    actual_ids = [row['id'] for row in draft]
    if actual_ids != expected_ids or len(set(actual_ids)) != len(actual_ids):
        return ['ID_SET_MISMATCH']
    approved = {(domain, term): target for domain, term, target, ok in rows}
    errors = []
    for (sid, domain, term, original), translated in zip(source, draft):
        target = approved[(domain, term)]
        # Exact case and word boundaries for this annotated fixture only.
        pattern = r'(?<![A-Za-z0-9_])' + re.escape(target) + r'(?![A-Za-z0-9_])'
        if not re.search(pattern, translated['text']):
            errors.append('TERM_MISMATCH:' + sid)
    return errors

def run_demo():
    bad_glossary = copy.deepcopy(BASE[:-1])
    bad_glossary.append(('auth', '키', 'credential key', True))
    bad_glossary.append(('ui', '빠른승인', 'fast approval', False))
    expected_glossary = [
        'APPROVED_COLLISION:auth/키',
        'MISSING_APPROVED_GLOSSARY:infra/작업큐',
        'UNAPPROVED_ADDITION:ui/빠른승인',
        'VERSION_MISMATCH',
    ]
    result = audit_glossary('terms-v1', bad_glossary)
    assert result == expected_glossary, result
    print('glossary_bad', result)
    assert audit_glossary(VERSION, BASE) == []
    print('glossary_recovery PASS; domains_of_same_term_preserved=True')
    bad_text = copy.deepcopy(GOOD)
    bad_text[2]['text'] = 'Find the item by the access key.'
    bad_text[4]['text'] = 'Change the batch.'
    bad_text[7]['text'] = 'Clear the queue.'
    result = audit_sentences(SOURCE, bad_text, BASE)
    assert result == ['TERM_MISMATCH:S03', 'TERM_MISMATCH:S05', 'TERM_MISMATCH:S08']
    print('sentences_bad', result)
    assert audit_sentences(SOURCE, GOOD, BASE) == []
    assert len({row[1] for row in BASE}) == 6
    assert len(SOURCE) == len(GOOD) == 8
    print('sentences_recovery PASS; korean_terms=6; domain_entries=8; sentences=8')
    print('translation_service_calls=0; source_and_bad_drafts_preserved=True')

if __name__ == '__main__':
    run_demo()

먼저 용어집이 준비되지 않으면 GLOSSARY_NOT_READY로 문장 대조를 멈춥니다. audit_sentences는 terms-v2가 선택됐다는 전제에서 승인 행을 재확인합니다. 실제 파일을 다룰 때에는 파일에서 읽은 버전을 audit_glossary에 먼저 전달해야 합니다. 버전 문자열만 바꾸어 붙인 파일이 같은 원본이라는 보장은 없으므로 원본 파일의 변경 이력이나 신뢰한 체크섬도 함께 남기는 것이 좋습니다.

정규식은 이 여덟 문장의 표시 용어를 찾는 작은 검사입니다. 모든 언어의 굴절·복합어·문맥 분석을 구현하지 않습니다. 승인 용어가 문장에 한 번 들어 있다는 사실만으로 원문 전체의 의미 보존, 새 정보 없음, 전체 용어 개수 일치를 증명하지도 않습니다.

실행 결과와 문장 사본의 복구

실제 로컬 출력은 다음과 같습니다. 오류 용어집은 4종으로 보류되고, 승인 원본을 다시 연결한 뒤 문장 사본의 S03·S05·S08에서 3건의 불일치가 나왔습니다.

glossary_bad ['APPROVED_COLLISION:auth/키', 'MISSING_APPROVED_GLOSSARY:infra/작업큐', 'UNAPPROVED_ADDITION:ui/빠른승인', 'VERSION_MISMATCH']
glossary_recovery PASS; domains_of_same_term_preserved=True
sentences_bad ['TERM_MISMATCH:S03', 'TERM_MISMATCH:S05', 'TERM_MISMATCH:S08']
sentences_recovery PASS; korean_terms=6; domain_entries=8; sentences=8
translation_service_calls=0; source_and_bad_drafts_preserved=True

S03은 품목의 item key 대신 인증 분야의 access key를 썼습니다. S05는 화면의 layout을 batch로 바꿨고 S08은 work queue를 queue로 줄였습니다. 이 세 오류는 해당 문장을 승인 용어 기준으로 수정한 새 사본에서만 다시 검사합니다. 원문·승인 원본·오류 사본은 유지하며, 오류 행을 지워 문장 수를 줄이지 않습니다.

대장에 남길 최소 기록과 적용 한계

아래 양식을 복사해 원본 위치를 내부 식별자로 기록합니다. 비밀 키의 실제 문자열은 적지 않습니다. auth/키는 단어 번역 항목일 뿐 키를 생성·교체하는 작업이 아닙니다.

대장 ID:
원문 파일 식별자 / 원문 버전:
선택한 용어집 파일 식별자 / 버전:
문장 ID / 사람이 확인한 분야 / 원문 용어:
지정 승인값 / 관측 번역:
오류: 버전 / 동일 분야 승인 충돌 / 미승인 추가 / 누락 / 번역 불일치
보류 근거 / 확인 담당자:
수정 사본 식별자 / 처리 사유 / 재검사 시각:
문장 수 보존 / 원본·오류 사본 보존:

기존 용어 번역표는 같은 한국어가 두 영어로 갈라졌는지를 세는 짧은 표입니다. 이 글의 완료 조건은 분야별 승인 원본과 버전을 정한 상태에서 충돌을 해결하는 것입니다. 문장별 분야가 없거나 승인 원본끼리 서로 충돌하면 자동 교정을 멈춥니다.

의무·가능·금지 같은 표현의 강도, 날짜·수량의 보존은 이 용어 대장만으로 검사하지 않습니다. 용어를 통일해도 “할 수 있다”가 “반드시 한다”로 바뀌면 별도 의미 검토가 필요합니다. 승인 판단을 원문·제안과 분리해 기록하는 방식은 엑셀 AI 결과 승인대장과 함께 적용할 수 있습니다.

작성자 소개