번역

Ren'Py는 비주얼 노벨 번역을 위한 포괄적인 프레임워크를 제공합니다. 번역할 수 있는 대상은 크게 네 가지입니다.

대사

스크립트의 주요 대사를 번역할 수 있으며 줄을 나누거나 합치고, 생략하거나 순서를 바꿀 수도 있습니다.

메뉴와 인터페이스 문자열

모든 인터페이스 텍스트를 번역할 수 있습니다.

이미지와 파일

특정 언어를 선택했을 때 사용할 대체 이미지와 다른 파일들을 포함할 수 있습니다.

스타일

언어에 따라 스타일을 변경하여 선택한 언어에 적합한 글꼴로 게임이 자동 전환되게 할 수 있습니다.

Ren'Py의 번역 지원은 현재 게임 제작자가 번역자에게 게임 스크립트를 제공하거나 직접 번역 템플릿을 만드는, 제작자가 승인한 번역에 중점을 둡니다. 승인되지 않은 번역에 대한 지원은 더 제한적입니다.

기본 언어와 추가 언어

Ren'Py는 각 게임이 하나의 기본 언어로 작성되어 있다고 가정합니다. 실제 언어와 관계없이 이를 None 언어라고 부릅니다. 예를 들어 영어로 작성한 게임에서는 영어가 None 언어입니다.

추가 언어는 Python 식별자로도 사용할 수 있는 이름으로 나타냅니다. 문자나 밑줄로 시작하고 그 뒤에는 문자, 숫자, 밑줄을 사용할 수 있습니다.

None 언어를 선택하면 대부분의 번역 기능이 꺼집니다. 다만 접근성 메뉴 등에서 사용하는 Ren'Py 내부의 내장 문자열은 예외입니다. 이 문자열들은 프로젝트 코드에는 없지만 배포 버전 게임에는 포함됩니다. game/tl/None/common.rpym 파일에서 확인할 수 있으며, 이 파일의 용도는 1) None 언어가 영어가 아닐 때 해당 문자열의 번역을 제공하고, 2) 제작자가 게임에 맞게 문자열을 수정하도록 하는 것입니다.

이 파일은 처음 생성될 때 프로젝트 생성 시점의 런처 언어로 내부 문자열을 번역합니다.

번역 파일 생성

프로젝트 스크립트가 있다면 Ren'Py 런처에서 프로젝트를 열고 번역 생성(Generate Translations)을 선택하여 번역 파일을 만들 수 있습니다. 런처가 생성할 언어의 이름을 묻고 번역 파일을 만들거나 갱신합니다.

번역 파일은 game 디렉터리의 "tl" 하위 디렉터리 안에 둡니다. 예를 들어 tutorial 프로젝트의 piglatin 번역을 생성하면 tutorial/game/tl/piglatin 아래에 번역 파일이 저장됩니다.

게임 스크립트 파일마다 번역 파일 하나를 만듭니다. Ren'Py로 만든 모든 게임에서 공통으로 사용하는 문자열의 번역을 담는 common.rpy 파일도 생성됩니다.

대사 번역

Ren'Py는 비주얼 노벨 엔진이므로 대부분의 번역 대상은 대사일 것입니다. 대사를 나누고 합치거나 순서를 바꾸고 완전히 생략할 수도 있는 유연한 프레임워크를 제공합니다.

번역 단위

번역의 기본 단위는 번역 가능한 문이 0개 이상 들어 있고 선택적으로 say 문 하나가 뒤따르는 블록입니다. 번역 가능한 문은 voice 문과 nvl 문입니다. 다음 게임을 예로 보겠습니다.

label start:
    e "Thank you for taking a look at the Ren'Py translation framework."

    show eileen happy

    e "We aim to provide a comprehensive framework for translating dialogue, strings, images, and styles."

    e "Pretty much everything your game needs!"

이를 여러 번역 단위로 나눕니다. 각 단위에 식별자를 부여하며, 단위 앞의 레이블과 단위 안의 문을 바탕으로 생성합니다. 여러 단위에 같은 번역 번호가 부여되는 경우 두 번째 이후 단위에 일련번호를 붙여 구분합니다.

위 예제에서 첫 번째 단위의 식별자는 start_636ae3f5이며 다음 문을 담습니다.

e "Thank you for taking a look at the Ren'Py translation framework."

두 번째 단위의 식별자는 start_bd1ad9e1m이며 다음을 담습니다.

e "We aim to provide a comprehensive framework for translating dialogue, strings, images, and styles."

세 번째 단위의 식별자는 start_9e949aac이며 다음을 담습니다.

e "Pretty much everything your game needs!"

이 단위들은 게임 스크립트를 로드할 때 Ren'Py가 자동으로 생성합니다.

translate 문

특정 언어의 번역을 생성하면 Ren'Py가 각 번역 단위에 대응하는 translate 문을 만듭니다. 위 스크립트에서는 다음을 생성합니다.

# game/script.rpy:95
translate piglatin start_636ae3f5:

    # e "Thank you for taking a look at the Ren'Py translation framework."
    e ""

# game/script.rpy:99
translate piglatin start_bd1ad9e1:

    # e "We aim to provide a comprehensive framework for translating dialogue, strings, images, and styles."
    e ""

# game/script.rpy:101
translate piglatin start_9e949aac:

    # e "Pretty much everything your game needs!"
    e ""

생성된 파일을 편집하여 번역할 수 있습니다. 완성된 번역은 다음과 같은 모습입니다.

# game/script.rpy:95
translate piglatin start_636ae3f5:
    # e "Thank you for taking a look at the Ren'Py translation framework."
    e "Ankthay ouyay orfay akingtay away ooklay atway ethay En'Pyray anslationtray ameworkfray."

# game/script.rpy:99
translate piglatin start_bd1ad9e1:

    # e "We aim to provide a comprehensive framework for translating dialogue, strings, images, and styles."
    e "Eway aimway otay ovidepray away omprehensivecay ameworkfray orfay anslatingtray ialogueday, ingsstray, imagesway, andway ylesstay."

# game/script.rpy:101
translate piglatin start_9e949aac:

    # e "Pretty much everything your game needs!"
    e "Ettypray uchmay everythingway ouryay amegay eedsnay!"

주 스크립트에서 블록에 도달하면 Ren'Py는 대응하는 translate 문이 있는지 확인합니다. 있으면 원래 블록 대신 translate 문을 실행하여 사용자에게 번역을 표시합니다.

더 복잡한 번역

원문의 각 줄과 일대일로 대응하는 번역을 translate 문에 넣을 필요는 없습니다. 예를 들어 긴 줄을 나눌 수 있습니다.

# game/script.rpy:99
translate piglatin start_bd1ad9e1:
    # e "We aim to provide a comprehensive framework for translating dialogue, strings, images, and styles."
    e "Eway aimway otay ovidepray away omprehensivecay ameworkfray..."
    e "...orfay anslatingtray ialogueday, ingsstray, imagesway, andway ylesstay."

문을 pass 문으로 대체하여 제거할 수도 있습니다.

# game/script.rpy:101
translate piglatin start_9e949aac:

    # e "Pretty much everything your game needs!"
    pass

조건문이나 Python 같은 대사 이외의 문을 실행할 수도 있습니다. 예를 들어 다음을:

e "You scored [points] points!"

다음과 같이 번역할 수 있습니다.

# game/script.rpy:103
translate piglatin start_36562aba:

    # e "You scored [points] points!"
    $ latin_points = to_roman_numerals(points)
    e "Ouyay oredscay [latin_points] ointspay!"

팁

이미 번역한 대사를 바꿀 때는 특히 주의하세요. 같은 레이블 안에서 여러 번 반복되는 대사라면 더욱 주의해야 합니다.

번역자에게 다시 번역을 요청하지 않고 원문의 대사를 바꾸고 싶을 때도 있습니다. 예를 들어 영어 오타는 러시아어로 번역하는 과정에서 이미 사라졌을 가능성이 큽니다.

say 문에 id 절을 넣어 사용할 번역 ID를 지정하면 됩니다. 예를 들면 다음과 같습니다.

label start:
    e "이 문장에는 원래 오타가 있었어요." id start_61b861a2

레이블을 추가하면 번역 과정에 혼란이 생길 수도 있습니다. 이를 방지하기 위해 hide 절이 있는 레이블은 번역을 생성할 때 무시합니다.

label ignored_by_translation hide:
    "..."

번역 블록에 Python 코드를 넣을 수 있지만 블록 밖에서 관찰할 수 있는 부수 효과가 없어야 합니다. 언어를 바꾸면 번역 블록이 다시 시작되어 부수 효과가 여러 번 발생하기 때문입니다.

이미지와 파일 번역

게임을 번역할 때 파일을 번역된 버전으로 교체해야 할 수 있습니다. 예를 들어 텍스트가 포함된 이미지는 다른 언어의 텍스트가 들어간 버전으로 바꾸는 것이 적절할 수 있습니다.

Ren'Py는 번역 디렉터리에서 이미지를 찾아 이를 처리합니다. 예를 들어 "piglatin" 언어를 사용 중이며 "library.png"를 로드하면 game/library.png보다 game/tl/piglatin/library.png를 우선 사용합니다.

파일이 game의 하위 디렉터리에 있으면 언어 디렉터리 아래에도 해당 디렉터리를 포함해야 합니다. 예를 들어 game/gui/main_menu.png를 번역하려면 game/tl/piglatin/gui/main_menu.png를 만듭니다.

스타일 번역

게임을 번역할 때 스타일, 특히 글꼴 관련 스타일을 바꾸어야 할 수 있습니다. Ren'Py는 translate style 블록과 translate python 블록으로 이를 처리합니다. 이 블록들에서 언어 관련 변수와 스타일을 바꿀 수 있습니다. 예를 들면 다음과 같습니다.

translate piglatin style default:
    font "stonecutter.ttf"

일반적으로 대사 글꼴은 gui.text_font로 설정합니다. 예외 화면, 접근성 메뉴, gui 메뉴 같은 시스템 텍스트의 글꼴은 gui.system_font로 바꿀 수 있습니다. 시스템 글꼴은 ASCII와 번역 언어를 모두 표시할 수 있어야 합니다. 다음과 같이 함께 설정할 수 있습니다.

translate piglatin python:
    gui.text_font = "stonecutter.ttf"
    gui.system_font = "Noto Sans.ttf"

게임 시작이나 언어 변경으로 언어가 활성화되면 Ren'Py는 스타일을 초기화 단계가 끝났을 때의 상태로 되돌립니다. 이어서 현재 언어에 연결된 모든 translate python 블록, 모든 style 블록, 모든 translate style 블록을 실행하며 파일에서 먼저 나오는 블록을 먼저 실행하도록 보장합니다. 마지막으로 스타일을 다시 빌드하여 변경 사항을 반영합니다.

스타일 번역은 어느 .rpy 파일에든 추가할 수 있습니다.

번역 지연 로딩

규모가 큰 게임은 모든 번역을 로드하는 데 오래 걸릴 수 있습니다. Ren'Py는 이를 줄이기 위해 번역 지연 로딩을 지원합니다. 사용하려면 다음을:

define config.defer_tl_scripts = True

options.rpy 파일이나 번역 스크립트보다 먼저 로드되는 파일에 추가합니다.

True이면 Ren'Py는 초기화할 때 tl/language 디렉터리의 스크립트 파일을 로드하지 않습니다. 대신 게임 시작이나 언어 변경으로 해당 언어가 처음 활성화될 때 로드합니다.

tl/language 디렉터리를 초기화 시점에 로드하지 않으므로 해당 파일에는 init 블록, python 블록, screen, image, transform 문 등 초기화 시점에 실행하는 문을 넣으면 안 됩니다. 파일 전체가 translate, translate python, translate style 블록으로만 구성되어야 합니다.

기본 언어

기본 언어는 다음 순서로 선택합니다.

번역 정보 스크린

개발자 메뉴(shift+D)에서 번역 정보 표시(Show Translation Info)를 선택하면 번역 정보를 볼 수 있습니다. 개발자가 아닌 경우 다음 코드로 표시할 수 있습니다.

show screen _translation_info

번역 액션, 함수, 변수

언어를 바꾸는 주요 방법은 Language 액션입니다.

Language(language)

게임 언어를 language로 바꿉니다.

language

번역할 언어를 나타내는 문자열입니다. None이면 게임 스크립트의 기본 언어를 사용합니다.

Language 액션으로 환경설정 스크린에 언어 선택을 추가할 수 있습니다.

frame:
    style_prefix "pref"
    has vbox

    label _("언어")
    textbutton "영어" action Language(None)
    textbutton "Igpay Atinlay" action Language("piglatin")

번역 관련 함수는 다음 두 가지입니다.

renpy.change_language(language, force: bool = False, rebuild: bool = False)

현재 언어를 language로 바꿉니다. 문자열로 지정하며 None이면 기본 언어를 사용합니다.

force

참이면 언어가 바뀌지 않아도 Python 코드를 다시 실행합니다.

rebuild

언어가 바뀌지 않아도 스타일을 강제로 다시 빌드합니다.

renpy.get_translation_identifier()

현재 문의 번역 식별자를 반환합니다.

renpy.get_translation_info(identifier=None, language=None)

지정한 식별자의 번역 정보를 반환합니다. language가 None이면 기본 텍스트의 정보를 반환합니다.

identifier

번역 식별자입니다. None이면 현재 표시 중인 텍스트의 정보를 가져옵니다.

language

언어 이름입니다. None이면 기본 텍스트의 정보를 가져옵니다.

사용 가능한 정보가 없으면 None을 반환합니다. 그렇지 않으면 다음 속성을 가진 객체를 반환합니다.

language
The language of the translation.
identifier
The identifier of the translation.
filename
The filename the translation is found in.
linenumber
The line number the translation is found on.
source
A list of strings that make up the translation. Only some statements can be included here,
including the say statements that make up most translations.
renpy.known_languages()

알려진 언어의 집합을 반환합니다. 기본 언어인 None은 포함하지 않습니다.

문자열 번역 관련 함수도 네 가지 있습니다.

_(s)

(밑줄 하나) s를 그대로 반환합니다. Ren'Py는 이 함수로 감싼 문자열을 찾아 번역 가능한 문자열 목록에 추가합니다. 실제로 표시할 때까지는 번역하지 않습니다.

__(s)

(밑줄 두 개) s를 현재 언어로 즉시 번역하여 반환합니다. 이 함수로 감싼 문자열은 번역 가능한 문자열 목록에 추가됩니다. 표시할 때 문자열 번역과 일치하면 이중으로 번역될 수 있습니다.

___(s)

(밑줄 세 개) s를 현재 언어로 즉시 번역합니다. 텍스트 보간 구문이 있으면 이 함수를 호출한 스코프의 지역 변수로 보간합니다. 표시할 때 문자열 번역과 일치하면 이중으로 번역될 수 있습니다.

_p(s)

문자열의 형식을 다듬고 번역 가능한 문자열로 표시합니다. Text 디스플레이어블에서 표시할 때 번역합니다. 다음과 같은 여러 줄 문자열을 정의하는 용도입니다.

define gui.about = _p("""
    These two lines will be combined together
    to form a long line.

    This line will be separate.
    """)

텍스트를 줄 단위로 나눈 뒤 각 줄의 앞뒤 공백을 제거하여 형식을 다듬습니다. 끝부분의 빈 줄은 제거합니다. 중간에 빈 줄이 있으면 빈 줄 하나로 문단을 구분합니다. {p} 태그는 줄을 나누지만 빈 줄은 추가하지 않습니다.

문자열 번역에서도 다음 구문으로 사용할 수 있습니다.

old "These two lines will be combined together to form a long line.\n\nThis line will be separate."
new _p("""
    These two lines will be combined together
    to form a long line. Bork bork bork.

    This line will be separate. Bork bork bork.
    """)
renpy.translate_string(s, language=renpy.object.Sentinel('default'))

s를 language로 즉시 번역하여 반환합니다. language가 Default이면 환경설정의 언어를 사용합니다. 이 함수로 감싼 문자열은 번역 가능한 문자열 목록에 추가되지 않습니다. 표시할 때 문자열 번역과 일치하면 이중으로 번역될 수 있습니다.

언어 관련 변수는 두 가지입니다. 하나는 게임의 기본 언어를 바꾸는 config.default_language입니다.

_preferences.language

현재 언어의 이름입니다. 기본 언어를 사용 중이면 None입니다. 읽기 전용 변수로 취급해야 합니다. 언어를 바꾸려면 renpy.change_language()를 호출합니다.

제작자가 승인하지 않은 번역

참고

제작자가 승인하지 않은 번역을 만들기 전에는 제작자에게 허가를 요청하는 것이 좋습니다.

Ren'Py는 게임 제작자의 적극적인 도움 없이 번역을 만드는 기능을 일부 지원합니다. 게임의 모든 문자열에서 문자열 번역 파일을 자동 생성하는 기능입니다. 대사 번역이 없는 대사에는 문자열 번역을 사용하므로 이 방법으로 게임을 번역할 수 있습니다.

문자열 번역 파일을 만들려면 다음 단계를 따릅니다.

  • RENPY_LANGUAGE 환경 변수를 번역할 언어로 설정합니다.

  • RENPY_UPDATE_STRINGS 환경 변수를 비어 있지 않은 값으로 설정합니다.

  • 모든 텍스트를 볼 때까지 게임을 플레이합니다.

game/tl/language/strings.rpy 파일에 모든 문자열을 담은 번역 템플릿이 갱신됩니다.

게임에 언어 변경 기능이 없으면 init python 블록에서 config.language를 번역 언어로 설정하는 것이 적절할 수 있습니다.

define config.language = None

None이 아니면 사용자가 이전에 선택한 언어보다 우선하여 게임 시작 시 사용할 언어를 설정합니다.

제작자의 승인 없이 번역하는 경우에도 대사에 문자열 번역을 사용하는 것과 함께 위에서 설명한 이미지 및 스타일 번역 방법을 사용할 수 있습니다.