Rails 국제화(I18n) API

Ruby I18n(국제화의 약자) 젬은 Ruby on Rails(Rails 2.2부터 포함)와 함께 제공되며, 영어 이외의 단일 사용자 정의 언어로 애플리케이션을 번역하거나 애플리케이션에 다국어 지원을 제공하기 위한 쉽게 사용할 수 있고 확장 가능한 프레임워크를 제공합니다.

“국제화"라는 프로세스는 일반적으로 애플리케이션의 모든 문자열과 기타 지역별 부분(날짜 또는 통화 형식 등)을 추상화하는 것을 의미합니다. "지역화” 프로세스는 이러한 부분에 대한 번역과 지역화된 형식을 제공하는 것을 의미합니다.[^1]

따라서 Rails 애플리케이션을 국제화하는 과정에서 다음을 수행해야 합니다:

  • I18n 지원을 확인합니다.
  • Rails에 로케일 사전을 어디에서 찾을 수 있는지 알려줍니다.
  • Rails에 로케일을 설정, 보존 및 전환하는 방법을 알려줍니다.

애플리케이션을 지역화하는 과정에서 다음 세 가지를 수행하고 싶을 것입니다:

  • Rails의 기본 로케일을 대체하거나 보완합니다 - 예: 날짜 및 시간 형식, 월 이름, Active Record 모델 이름 등.
  • 애플리케이션의 문자열을 키가 있는 사전으로 추상화합니다 - 예: 플래시 메시지, 뷰의 정적 텍스트 등.
  • 결과 사전을 어딘가에 저장합니다.

이 가이드는 I18n API를 안내하고 처음부터 Rails 애플리케이션을 국제화하는 자습서를 포함합니다.

이 가이드를 읽고 나면 다음을 알게 될 것입니다:

  • Ruby on Rails에서 I18n이 어떻게 작동하는지
  • RESTful 애플리케이션에서 다양한 방식으로 I18n을 올바르게 사용하는 방법
  • Active Record 오류 또는 Action Mailer 이메일 제목을 번역하는 방법
  • 애플리케이션 번역 프로세스를 더 발전시키기 위한 기타 도구

참고: Ruby I18n 프레임워크는 Rails 애플리케이션의 국제화/지역화를 위한 모든 필요한 수단을 제공합니다. 추가 기능이나 기능을 추가하기 위해 다양한 젬을 사용할 수도 있습니다. 자세한 내용은 rails-i18n 젬을 참조하세요.

Ruby on Rails의 I18n 작동 방식

국제화는 복잡한 문제입니다. 자연어는 (예: 복수형 규칙) 많은 면에서 서로 다르기 때문에 모든 문제를 한 번에 해결할 수 있는 도구를 제공하기는 어렵습니다. 이러한 이유로 Rails I18n API는 다음에 중점을 둡니다:

  • 기본적으로 영어와 유사한 언어에 대한 지원 제공
  • 다른 언어에 대해 모든 것을 쉽게 사용자 정의하고 확장할 수 있게 만들기

이 솔루션의 일부로, Rails 프레임워크의 모든 정적 문자열 - 예: Active Record 유효성 검사 메시지, 날짜 및 시간 형식 - 은 국제화되었습니다. 애플리케이션의 지역화는 이러한 문자열에 대한 번역된 값을 원하는 언어로 정의하는 것을 의미합니다.

애플리케이션의 콘텐츠(예: 블로그 게시물 번역)를 저장, 업데이트하려면 모델 콘텐츠 번역 섹션을 참조하세요.

라이브러리의 전반적인 아키텍처

따라서 Ruby I18n 젬은 두 부분으로 나뉩니다:

  • I18n 프레임워크의 공개 API - 라이브러리가 작동하는 방식을 정의하는 공개 메서드가 포함된 Ruby 모듈
  • 이러한 메서드를 구현하는 기본 백엔드(의도적으로 Simple 백엔드라고 명명됨)

사용자로서 항상 I18n 모듈의 공개 메서드만 액세스해야 하지만, 백엔드의 기능을 알고 있는 것이 유용합니다.

참고: 제공된 Simple 백엔드를 관계형 데이터베이스, GetText 사전 또는 유사한 것을 저장하는 더 강력한 백엔드로 교체할 수 있습니다. 다른 백엔드 사용 섹션을 참조하세요.

공개 I18n API

I18n API의 가장 중요한 메서드는 다음과 같습니다:

translate # 텍스트 번역 조회
localize  # 로컬 형식으로 날짜 및 시간 개체 지역화

이들에게는 #t와 #l의 별칭이 있어 다음과 같이 사용할 수 있습니다:

I18n.t 'store.title'
I18n.l Time.now

또한 다음 속성에 대한 속성 리더와 작성기가 있습니다:

load_path                 # 사용자 정의 번역 파일 알리기
locale                    # 현재 로케일 가져오기 및 설정
default_locale            # 기본 로케일 가져오기 및 설정
available_locales         # 애플리케이션에 사용 가능한 허용된 로케일
enforce_available_locales # 로케일 권한 적용(true 또는 false)
exception_handler         # 다른 exception_handler 사용
backend                   # 다른 백엔드 사용

따라서 다음 장에서 처음부터 Rails 애플리케이션에 대한 I18n 지원을 설정해 보겠습니다!

국제화를 위한 Rails 애플리케이션 설정

I18n 지원을 위해 Rails 애플리케이션을 실행하는 데는 몇 가지 단계가 필요합니다.

I18n 모듈 구성

규약 대 구성 철학을 따라, Rails I18n은 합리적인 기본 번역 문자열을 제공합니다. 다른 번역 문자열이 필요한 경우 이를 재정의할 수 있습니다.

Rails는 config/locales 디렉토리의 모든 .rb.yml 파일을 번역 로드 경로에 자동으로 추가합니다.

이 디렉토리의 기본 en.yml 로케일에는 샘플 번역 문자열 쌍이 포함되어 있습니다:

en:
  hello: "Hello world"

이는 :en 로케일에서 hello 키가 Hello world 문자열에 매핑된다는 의미입니다. Rails 내부의 모든 문자열은 이와 같은 방식으로 국제화됩니다. 예를 들어 Active Model 유효성 검사 메시지는 activemodel/lib/active_model/locale/en.yml 파일에, 날짜 및 시간 형식은 activesupport/lib/active_support/locale/en.yml 파일에 있습니다. YAML 또는 표준 Ruby 해시를 사용하여 기본(Simple) 백엔드에 번역을 저장할 수 있습니다.

I18n 라이브러리는 영어기본 로케일로 사용할 것입니다. 즉, 다른 로케일이 설정되지 않은 경우 번역 조회에 :en이 사용됩니다.

참고: i18n 라이브러리는 일부 토론 후 로케일 키에 대해 실용적인 접근 방식을 취합니다. 즉, :en, :pl, :th 또는 :es(체코어, 태국어 및 스페인어용)과 같이 로케일(언어) 부분만 포함하고 지역(지역 설정) 부분은 포함하지 않습니다. :en-US 또는 :en-GB와 같이 “언어"와 "지역 설정” 또는 “방언"을 구분하는 전통적인 방식을 사용합니다. 그러나 다양한 언어 그룹 내에서도 중요한 지역적 차이가 있을 수 있습니다. 예를 들어 :"en-US" 로케일에서는 통화 기호로 $를 사용하지만 :"en-GB"에서는 £를 사용합니다. 지역 및 기타 설정을 이와 같이 구분하는 것을 막지 않습니다. 단순히 :"en-GB" 사전에 전체 "영어 - 영국” 로케일을 제공하면 됩니다.

번역 로드 경로(I18n.load_path)는 자동으로 로드될 파일의 경로 배열입니다. 이 경로를 구성하면 번역 디렉토리 구조와 파일 명명 체계를 사용자 정의할 수 있습니다.

참고: 백엔드는 번역이 처음 조회될 때 이러한 번역을 지연 로드합니다. 이 백엔드는 번역이 이미 알려진 후에도 다른 것으로 교체할 수 있습니다.

기본 로케일과 번역 로드 경로를 config/application.rb에서 다음과 같이 변경할 수 있습니다:

config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')]
config.i18n.default_locale = :de

로드 경로는 번역을 조회하기 전에 지정되어야 합니다. 초기화기 대신 config/application.rb에서 기본 로케일을 변경하려면:

# config/initializers/locale.rb

# I18n 라이브러리가 번역 파일을 검색할 위치
I18n.load_path += Dir[Rails.root.join('lib', 'locale', '*.{rb,yml}')]

# 애플리케이션에 허용되는 로케일
I18n.available_locales = [:en, :pt]

# 기본 로케일을 :en 이외의 것으로 설정
I18n.default_locale = :pt

I18n.load_path에 직접 추가하는 것이 아니라 애플리케이션의 구성된 I18n에 추가하는 것에 유의하세요. 그렇지 않으면 외부 젬의 번역을 재정의하지 않습니다.

요청 간 로케일 관리

다국어 애플리케이션은 여러 로케일을 지원해야 할 것입니다. 이를 달성하려면 모든 문자열이 해당 요청의 수명 동안 원하는 로케일을 사용하여 번역되도록 각 요청 시작 시 로케일을 설정해야 합니다.

기본 로케일은 I18n.locale= 또는 I18n.with_locale을 사용하지 않는 한 모든 번역에 사용됩니다.

I18n.locale은 모든 컨트롤러에서 일관되게 설정되지 않으면 동일한 스레드/프로세스에서 후속 요청으로 누출될 수 있습니다. 예를 들어 한 POST 요청에서 I18n.locale = :es를 실행하면 로케일을 설정하지 않는 모든 후속 컨트롤러 요청에 영향을 미치지만 해당 특정 스레드/프로세스에서만 그렇습니다. 따라서 I18n.locale = 대신 I18n.with_locale을계속:

ApplicationController에서 around_action을 사용하여 로케일을 설정할 수 있습니다:

around_action :switch_locale

def switch_locale(&action)
  locale = params[:locale] || I18n.default_locale
  I18n.with_locale(locale, &action)
end

이 예제는 URL 쿼리 매개변수를 사용하여 로케일을 설정하는 방법을 보여줍니다(예: http://example.com/books?locale=pt). 이 접근 방식을 사용하면 http://localhost:3000?locale=pt는 포르투갈어 지역화를, http://localhost:3000?locale=de는 독일어 지역화를 로드합니다.

로케일은 여러 가지 다른 접근 방식을 사용하여 설정할 수 있습니다.

도메인 이름에서 로케일 설정

옵션 중 하나는 애플리케이션이 실행되는 도메인 이름에서 로케일을 설정하는 것입니다. 예를 들어 www.example.com에서는 영어(또는 기본) 로케일을 로드하고 www.example.es에서는 스페인어 로케일을 로드하고 싶습니다. 따라서 최상위 도메인 이름이 로케일 설정에 사용됩니다. 이에는 여러 가지 장점이 있습니다:

  • 로케일이 URL의 명확한 부분입니다.
  • 콘텐츠가 어떤 언어로 표시되는지 사람들이 직관적으로 이해할 수 있습니다.
  • Rails에서 구현하기가 매우 간단합니다.
  • 검색 엔진은 다른 언어의 콘텐츠가 서로 연결된 다른 도메인에 있는 것을 좋아하는 것 같습니다.

ApplicationController에서 다음과 같이 구현할 수 있습니다:

around_action :switch_locale

def switch_locale(&action)
  locale = extract_locale_from_tld || I18n.default_locale
  I18n.with_locale(locale, &action)
end

# TLD에서 로케일을 가져오거나 해당 로케일을 사용할 수 없는 경우 +nil+ 반환
# 로컬에서 이것을 시도하려면 /etc/hosts 파일에 다음과 같은 내용을 추가해야 합니다:
#   127.0.0.1 application.com
#   127.0.0.1 application.it
#   127.0.0.1 application.pl
def extract_locale_from_tld
  parsed_locale = request.host.split('.').last
  I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil
end

하위 도메인에서 로케일을 설정할 수도 있습니다:

# 요청 하위 도메인에서 로케일 코드 가져오기(예: http://it.application.local:3000)
# 로컬에서 이것을 시도하려면 /etc/hosts 파일에 다음과 같은 내용을 추가해야 합니다:
#   127.0.0.1 gr.application.local
def extract_locale_from_subdomain
  parsed_locale = request.subdomains.first
  I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil
end

애플리케이션에 로케일 전환 메뉴가 포함된 경우 다음과 같이 표시할 수 있습니다:

link_to("Deutsch", "#{APP_CONFIG[:deutsch_website_url]}#{request.env['PATH_INFO']}")

이 솔루션에는 앞서 언급한 장점이 있지만 다른 도메인에서 다른 지역화(“언어 버전”)를 제공할 수 없거나 제공하고 싶지 않을 수 있습니다. 가장 명확한 솔루션은 URL 매개변수(또는 요청 경로)에 로케일 코드를 포함하는 것입니다.

URL 매개변수에서 로케일 설정

로케일을 설정(및 전달)하는 가장 일반적인 방법은 URL 매개변수에 포함하는 것입니다. 첫 번째 예에서 I18n.with_locale(params[:locale], &action) aroundaction_과 같이 했습니다. 이 경우 www.example.com/books?locale=ja 또는 www.example.com/ja/books와 같은 URL을 원할 것입니다.

이 접근 방식은 도메인 이름에서 로케일을 설정하는 것과 거의 같은 장점 집합을 가집니다. 즉, RESTful하고 World Wide Web의 나머지 부분과 일치합니다. 그러나 구현하는 데 약간 더 많은 작업이 필요합니다.

params에서 로케일을 가져오고 이에 따라 설정하는 것은 어렵지 않습니다. 그러나 모든 URL에 명시적 옵션을 포함하고 따라서 요청을 통해 전달하는 것은 지루하고 거의 불가능할 것입니다.

Rails에는 ApplicationController#default_url_options에서 “URL에 대한 동적 결정을 중앙 집중화"하는 인프라가 있으며, 이는 이 시나리오에서 정확히 유용합니다. 즉, url_for 및 이에 의존하는 헬퍼 메서드에 대한 "기본값"을 설정할 수 있습니다(default_url_options 구현/재정의).

그런 다음 ApplicationController에 다음과 같은 내용을 포함할 수 있습니다:

# app/controllers/application_controller.rb
def default_url_options
  { locale: I18n.locale }
end

url_for에 의존하는 모든 헬퍼 메서드(예: 명명된 경로 헬퍼 root_path 또는 root_url, 리소스 경로 헬퍼 books_path 또는 books_url 등)는 이제 자동으로 쿼리 문자열에 로케일을 포함합니다. 예: http://localhost:3001/?locale=ja.

이 방법으로 만족할 수 있습니다. 그러나 로케일이 모든 URL의 끝에 "매달려” 있어 URL 가독성에 영향을 미칩니다. 또한 아키텍처 관점에서 로케일은 일반적으로 애플리케이션 도메인의 다른 부분보다 계층적으로 높습니다. URL은 이를 반영해야 합니다.

다음과 같은 URL을 원할 것입니다: http://www.example.com/en/books(영어 로케일 로드) 및 http://www.example.com/nl/books(네덜란드어 로케일 로드). 위의 “defaulturloptions 재정의” 전략으로 이를 달성할 수 있습니다. 단순히 scope를 사용하여 경로를 설정하면 됩니다:

# config/routes.rb
scope "/:locale" do
  resources :books
end

이제 books_path 메서드를 호출하면 기본 로케일의 "/en/books"를 얻게 됩니다. http://localhost:3001/nl/books와 같은 URL은 네덜란드어 로케일을 로드하고 이후 books_path 호출은 "/nl/books"를 반환합니다(로케일이 변경되었기 때문).

경고. default_url_options의 반환 값은 요청별로 캐시되므로, 각 반복에서 해당 I18n.locale을 설정하는 루프에서 도우미를 호출하여 선택기의 URL을 생성할 수 없습니다. 대신 I18n.locale을 변경하지 않고 명시적 :locale 옵션을 도우미에 전달하거나 request.original_fullpath를 편집하세요.

경로에 로케일 사용을 강제하고 싶지 않은 경우 선택적 경로 범위(괄호로 표시)를 사용할 수 있습니다:

# config/routes.rb
scope "(:locale)", locale: /en|nl/ do
  resources :books
end

이 접근 방식을 사용하면 http://localhost:3001/books와 같이 로케일을 지정하지 않고 리소스에 액세스할 때 Routing Error가 발생하지 않습니다. 기본 로케일을 지정하지 않은 경우 사용하는 데 유용합니다.

물론 애플리케이션의 루트 URL(일반적으로 “홈페이지” 또는 “대시보드”)에 대해 특별한 주의를 기울여야 합니다. http://localhost:3001/nl과 같은 URL은 자동으로 작동하지 않습니다. 왜냐하면 routes.rbroot to: "dashboard#index" 선언은 로케일을 고려하지 않기 때문입니다. (그리고 그렇게 해야 합니다: 루트 URL은 하나뿐입니다.)

다음과 같은 URL을 매핑해야 할 것입니다:

# config/routes.rb
get '/:locale' => 'dashboard#index'

경로 순서에 특별히 주의를 기울이세요. 이 경로 선언이 다른 경로를 “먹어버리지” 않도록 해야 합니다. (이를 root :to 선언 바로 앞에 추가하는 것이 좋습니다.)

참고: 경로 작업을 단순화하는 다양한 젬을 살펴보세요: routing_filter, route_translator.

사용자 기본 설정에서 로케일 설정

인증된 사용자가 있는 애플리케이션은 사용자가 애플리케이션 인터페이스를 통해 로케일 기본 설정을 설정할 수 있도록 허용할 수 있습니다. 이 접근 방식에서는 사용자가 선택한 로케일 기본 설정이 데이터베이스에 저장되고 해당 사용자의 인증된 요청에 사용됩니다.

around_action :switch_locale

def switch_locale(&action)
  locale = current_user.try(:locale) || I18n.default_locale
  I18n.with_locale(locale, &action)
end

암시적 로케일 선택

요청에 명시적 로케일이 설정되지 않은 경우(위의 방법 중 하나를 통해) 애플리케이션은 원하는 로케일을 추론하려고 시도해야 합니다.

Accept-Language 헤더에서 로케일 추론

Accept-Language HTTP 헤더는 요청 응답에 대한 선호 언어를 나타냅니다. 브라우저는 사용자의 언어 기본 설정에 따라 이 헤더 값을 설정하므로 로케일을 추론할 때 첫 번째 선택이 됩니다.

Accept-Language 헤더를 사용하는 간단한 구현은 다음과 같습니다:

def switch_locale(&action)
  logger.debug "* Accept-Language: #{request.env['HTTP_ACCEPT_LANGUAGE']}"
  locale = extract_locale_from_accept_language_header
  logger.debug "* Locale set to '#{locale}'"
  I18n.with_locale(locale, &action)
end

private
  def extract_locale_from_accept_language_header
    request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first
  end

실제로는 이 문제를 안정적으로 해결하기 위해 더 강력한 코드가 필요합니다. Iain Hecker의 httpacceptlanguage 라이브러리 또는 Ryan Tomayko의 locale Rack 미들웨어가 이 문제에 대한 솔루션을 제공합니다.

IP 지오로케이션에서 로케일 추론

요청을 보내는 클라이언트의 IP 주소를 사용하여 클라이계속:

IP 지오로케이션에서 로케일 추론

요청을 보내는 클라이언트의 IP 주소를 사용하여 클라이언트의 지역을 추론하고 따라서 해당 로케일을 추론할 수 있습니다. GeoLite2 Country 서비스 또는 geocoder 젬과 같은 서비스를 사용하여 이 접근 방식을 구현할 수 있습니다.

일반적으로 이 접근 방식은 언어 헤더를 사용하는 것보다 훨씬 신뢰할 수 없으며 대부분의 웹 애플리케이션에 권장되지 않습니다.

세션 또는 쿠키에서 로케일 저장

경고: 선택한 로케일을 세션 또는 쿠키에 저장하고 싶을 수 있습니다. 그러나 이렇게 하지 마세요. 로케일은 투명해야 하며 URL의 일부여야 합니다. 그렇지 않으면 웹 자체에 대한 기본 가정을 깨뜨리게 됩니다. 즉, 친구에게 URL을 보내면 동일한 페이지와 콘텐츠를 볼 수 있어야 합니다. 이를 RESTful이라고 하는 fancy 단어가 있습니다. *Stefan Tilkov의 기사에서 RESTful 접근 방식에 대해 자세히 알아보세요. 때로는 이 규칙의 예외가 있으며 아래에서 논의됩니다.

국제화 및 지역화

좋습니다! 이제 Ruby on Rails 애플리케이션에 대한 I18n 지원을 초기화하고 어떤 로케일을 사용할지, 요청 간에 어떻게 보존할지 알려주었습니다.

다음으로 모든 로케일 특정 요소를 추상화하여 Rails 애플리케이션을 국제화해야 합니다. 마지막으로 이러한 추상화에 대한 필요한 번역을 제공하여 지역화해야 합니다.

다음 예를 고려해 보겠습니다:

# config/routes.rb
Rails.application.routes.draw do
  root to: "home#index"
end
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  around_action :switch_locale

  def switch_locale(&action)
    locale = params[:locale] || I18n.default_locale
    I18n.with_locale(locale, &action)
  end
end
# app/controllers/home_controller.rb
class HomeController < ApplicationController
  def index
    flash[:notice] = "Hello Flash"
  end
end
<!-- app/views/home/index.html.erb -->
<h1>Hello World</h1>
<p><%= flash[:notice] %></p>

rails i18n demo untranslated

지역화된 코드 추상화

우리의 코드에는 응답에 렌더링될 두 개의 영어 문자열(“Hello Flash” 및 “Hello World”)이 있습니다. 이 코드를 국제화하려면 이러한 문자열을 각 문자열에 적절한 키를 사용하여 Rails의 #t 헬퍼로 대체해야 합니다:

# app/controllers/home_controller.rb
class HomeController < ApplicationController
  def index
    flash[:notice] = t(:hello_flash)
  end
end
<!-- app/views/home/index.html.erb -->
<h1><%= t :hello_world %></h1>
<p><%= flash[:notice] %></p>

이제 이 뷰가 렌더링되면 :hello_world:hello_flash 키에 대한 번역이 누락되었다는 오류 메시지가 표시됩니다.

rails i18n demo translation missing

참고: Rails는 t(translate) 헬퍼 메서드를 뷰에 추가하므로 I18n.t를 모두 작성할 필요가 없습니다. 또한 이 헬퍼는 누락된 번역을 캐치하고 결과 오류 메시지를 <span class="translation_missing">으로 래핑합니다.

국제화된 문자열에 대한 번역 제공

번역 사전 파일에 누락된 번역을 추가합니다:

# config/locales/en.yml
en:
  hello_world: Hello world!
  hello_flash: Hello flash!
# config/locales/pirate.yml
pirate:
  hello_world: Ahoy World
  hello_flash: Ahoy Flash

default_locale이 변경되지 않았기 때문에 번역은 :en 로케일을 사용하고 응답은 영어 문자열을 렌더링합니다:

rails i18n demo translated to English

URL을 통해 로케일을 해적 로케일(http://localhost:3000?locale=pirate)로 설정하면 응답이 해적 문자열을 렌더링합니다:

rails i18n demo translated to pirate

참고: 새 로케일 파일을 추가할 때는 서버를 다시 시작해야 합니다.

YAML(.yml) 또는 일반 Ruby(.rb) 파일을 사용하여 SimpleStore에 번역을 저장할 수 있습니다. Rails 개발자 사이에서 YAML이 선호되는 옵션입니다. 그러나 큰 단점이 있습니다. YAML은 공백과 특수 문자에 매우 민감하므로 애플리케이션이 사전을 제대로 로드하지 못할 수 있습니다. Ruby 파일은 첫 번째 요청에 애플리케이션을 충돌시킬 것이므로 무엇이 잘못되었는지 쉽게 찾을 수 있습니다. (YAML 사전에서 “이상한 문제"가 발생하는 경우 관련 부분을 Ruby 파일에 넣어보세요.)

번역이 YAML 파일에 저장된 경우 특정 키는 이스케이프해야 합니다. 그것들은:

  • true, on, yes
  • false, off, no

예:

# config/locales/en.yml
en:
  success:
    'true':  'True!'
    'on':    'On!'
    'false': 'False!'
  failure:
    true:    'True!'
    off:     'Off!'
    false:   'False!'
I18n.t 'success.true'  # => 'True!'
I18n.t 'success.on'    # => 'On!'
I18n.t 'success.false' # => 'False!'
I18n.t 'failure.false' # => Translation Missing
I18n.t 'failure.off'   # => Translation Missing
I18n.t 'failure.true'  # => Translation Missing

번역에 변수 전달

애플리케이션을 성공적으로 국제화하는 데 고려해야 할 핵심 사항 중 하나는 지역화된 코드를 추상화할 때 문법 규칙에 대한 잘못된 가정을 하지 않는 것입니다. 한 로케일에서 기본적으로 보이는 문법 규칙은 다른 로케일에서는 적용되지 않을 수 있습니다.

부적절한 추상화는 다음 예에서 보여줍니다. 여기서는 번역의 다양한 부분에 대한 순서 가정을 하고 있습니다. Rails는 다음 경우를 처리하기 위해 number_to_currency 헬퍼를 제공합니다.

<!-- app/views/products/show.html.erb -->
<%= "#{t('currency')}#{@product.price}" %>
# config/locales/en.yml
en:
  currency: "$"
# config/locales/es.yml
es:
  currency: "€"

제품 가격이 10인 경우 스페인어에 대한 올바른 번역은 "10 €"이지만 추상화로는 이를 제공할 수 없습니다.

적절한 추상화를 위해 I18n 젬은 변수 보간이라는 기능을 제공합니다. 이를 통해 번역 정의에 변수를 사용하고 이러한 변수의 값을 번역 메서드에 전달할 수 있습니다.

적절한 추상화는 다음 예에서 보여줍니다:

<!-- app/views/products/show.html.erb -->
<%= t('product_price', price: @product.price) %>
# config/locales/en.yml
en:
  product_price: "$%{price}"
# config/locales/es.yml
es:
  product_price: "%{price} €"

모든 문법 및 구두점 결정은 정의 자체에서 이루어지므로 추상화가 올바른 번역을 제공할 수 있습니다.

참고: defaultscope 키워드는 예약되어 있으며 변수 이름으로 사용할 수 없습니다. 사용하면 I18n::ReservedInterpolationKey 예외가 발생합니다. 번역에 보간 변수가 필요하지만 #translate에 전달되지 않은 경우 I18n::MissingInterpolationArgument 예외가 발생합니다.

날짜/시간 형식 추가

좋습니다! 이제 뷰에 타임스탬프를 추가하여 날짜/시간 지역화 기능도 데모할 수 있습니다. Time 개체를 I18n.l 또는(선호) #l 헬퍼에 전달하여 시간 형식을 지역화할 수 있습니다. :format 옵션을 전달하여 형식을 선택할 수 있습니다. 기본적으로 :default 형식이 사용됩니다.

<!-- app/views/home/index.html.erb -->
<h1><%= t :hello_world %></h1>
<p><%= flash[:notice] %></p>
<p><%= l Time.now, format: :short %></p>

그리고 우리의 해적 번역 파일에 시간 형식을 추가해 보겠습니다(영어의 기본값에 이미 있습니다):

# config/locales/pirate.yml
pirate:
  time:
    formats:
      short: "arrrround %H'ish"

그러면 다음과 같이 표시됩니다:

rails i18n demo localized time to pirate

팁: 지금은 I18n 백엔드가 예상대로 작동하려면 다른 날짜/시간 형식을 더 추가해야 할 수 있습니다(적어도 ‘pirate’ 로케일의 경우). 물론 누군가가 이미 다양한 로케일에 대한 Rails의 기본값을 번역했을 가능성이 높습니다. GitHub의 rails-i18n 리포지토리에서 다양한 로케일 파일을 찾을 수 있습니다. config/locales/ 디렉토리에 이러한 파일을 넣으면 자동으로 사용할 준비가 됩니다.

다른 로케일에 대한 변화 규칙

Rails를 통해 영어 이외의 로케일에 대한 변화 규칙(예: 단수화 및 복수화)을 정의할 수 있습니다. config/initializers/inflections.rb에서 이러한 규칙을 여러 로케일에 대해 정의할 수 있습니다. 이 초기화기에는 영어에 대한 추가 규칙의 기본 예가 포함되어 있습니다. 필요에 따라 다른 로케일에 대해 해당 형식을 따르세요.

지역화된 뷰

BooksController가 애플리케이션에 있다고 가정해 보겠습니다. index 작업은 app/views/books/index.html.erb 템플릿에서 콘텐츠를 렌더링합니다. 이 템플릿의 지역화된 변형index.es.html.erb를 동일한 디렉토리에 배치하면 로케일이 :es로 설정된 경우 이 템플릿의 콘텐츠가 렌더링됩니다. 로케일이 기본 로케일로 설계속:

지역화된 뷰

BooksController가 애플리케이션에 있다고 가정해 보겠습니다. index 작업은 app/views/books/index.html.erb 템플릿에서 콘텐츠를 렌더링합니다. 이 템플릿의 지역화된 변형index.es.html.erb를 동일한 디렉토리에 배치하면 로케일이 :es로 설정된 경우 이 템플릿의 콘텐츠가 렌더링됩니다. 로케일이 기본 로케일로 설정된 경우 일반 index.html.erb 뷰가 사용됩니다. (향후 Rails 버전에서는 이 자동 지역화를 public의 자산에도 적용할 수 있습니다.)

이 기능을 사용하면 예를 들어 정적 콘텐츠가 많은 경우 YAML 또는 Ruby 사전 내부에 넣는 것보다 편리할 수 있습니다. 그러나 나중에 템플릿을 변경하려면 모두에게 변경 사항을 전파해야 한다는 점을 유의하세요.

로케일 파일 구성

기본 SimpleStore와 함께 제공되는 i18n 라이브러리를 사용하는 경우 사전은 디스크의 일반 텍스트 파일에 저장됩니다. 애플리케이션의 모든 부분에 대한 번역을 하나의 파일에 넣는 것은 관리하기 어려울 수 있습니다. 의미 있는 계층 구조로 이러한 파일을 저장할 수 있습니다.

예를 들어 config/locales 디렉토리는 다음과 같이 보일 수 있습니다:

|-defaults
|---es.yml
|---en.yml
|-models
|---book
|-----es.yml
|-----en.yml
|-views
|---defaults
|-----es.yml
|-----en.yml
|---books
|-----es.yml
|-----en.yml
|---users
|-----es.yml
|-----en.yml
|---navigation
|-----es.yml
|-----en.yml

이렇게 하면 모델 및 모델 속성 이름을 뷰 내부의 텍스트와 구분할 수 있고 이 모두를 "기본값”(예: 날짜 및 시간 형식)과 구분할 수 있습니다. i18n 라이브러리의 다른 저장소는 이러한 구분을 제공할 수 있는 다른 수단을 제공할 수 있습니다.

참고: Rails의 기본 로케일 로드 메커니즘은 여기와 같이 중첩된 사전을 로드하지 않습니다. 따라서 이 작업을 수행하려면 Rails에 명시적으로 추가해야 합니다:

# config/application.rb
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]

I18n API 기능 개요

이제 i18n 라이브러리 사용에 대한 좋은 이해가 있고 기본 Rails 애플리케이션을 국제화하는 방법을 알고 있습니다. 다음 장에서는 이 기능을 더 자세히 다룰 것입니다.

이러한 장에서는 I18n.translate 메서드와 translate 뷰 헬퍼 메서드의 예를 모두 보여줄 것입니다(뷰 헬퍼 메서드가 제공하는 추가 기능 참고).

다음과 같은 기능이 다루어집니다:

  • 번역 조회
  • 번역에 데이터 보간
  • 번역 복수화
  • 안전한 HTML 번역 사용(뷰 헬퍼 메서드만)
  • 날짜, 숫자, 통화 등 지역화

번역 조회

기본 조회, 범위 및 중첩 키

번역은 기호 또는 문자열 키로 조회할 수 있으므로 이러한 호출은 동등합니다:

I18n.t :message
I18n.t 'message'

translate 메서드는 또한 번역 키에 대한 “네임스페이스” 또는 범위를 지정하는 데 사용할 수 있는 :scope 옵션을 받습니다:

I18n.t :record_invalid, scope: [:activerecord, :errors, :messages]

이는 Active Record 오류 메시지의 :record_invalid 메시지를 조회합니다.

또한 키와 범위를 모두 점으로 구분된 키로 지정할 수 있습니다:

I18n.translate "activerecord.errors.messages.record_invalid"

따라서 다음 호출은 모두 동등합니다:

I18n.t 'activerecord.errors.messages.record_invalid'
I18n.t 'errors.messages.record_invalid', scope: :activerecord
I18n.t :record_invalid, scope: 'activerecord.errors.messages'
I18n.t :record_invalid, scope: [:activerecord, :errors, :messages]

기본값

:default 옵션이 제공되면 번역이 누락된 경우 해당 값이 반환됩니다:

I18n.t :missing, default: 'Not here'
# => 'Not here'

:default 값이 기호인 경우 키로 사용되어 번역됩니다. 기본값으로 여러 값을 제공할 수 있습니다. 결과가 값인 첫 번째 항목이 반환됩니다.

예를 들어 다음은 먼저 :missing 키를 번역하려 하고 그 다음 :also_missing을 번역하려 합니다. 둘 다 결과를 내지 않으므로 “Not here” 문자열이 반환됩니다:

I18n.t :missing, default: [:also_missing, 'Not here']
# => 'Not here'

벌크 및 네임스페이스 조회

여러 번역을 한 번에 조회하려면 키 배열을 전달할 수 있습니다:

I18n.t [:odd, :even], scope: 'errors.messages'
# => ["must be odd", "must be even"]

또한 키가 (잠재적으로 중첩된) 그룹화된 번역 해시로 번역될 수 있습니다. 예를 들어 다음과 같이 모든 Active Record 오류 메시지를 해시로 받을 수 있습니다:

I18n.t 'errors.messages'
# => {:inclusion=>"is not included in the list", :exclusion=> ... }

벌크 번역 해시에 보간을 수행하려면 deep_interpolation: true 매개변수를 전달해야 합니다. 다음과 같은 사전이 있는 경우:

en:
  welcome:
    title: "Welcome!"
    content: "Welcome to the %{app_name}"

설정 없이는 중첩 보간이 무시됩니다:

I18n.t 'welcome', app_name: 'book store'
# => {:title=>"Welcome!", :content=>"Welcome to the %{app_name}"}

I18n.t 'welcome', deep_interpolation: true, app_name: 'book store'
# => {:title=>"Welcome!", :content=>"Welcome to the book store"}

“게으른” 조회

Rails는 내부에서 로케일을 조회하는 편리한 방법을 구현합니다. 다음과 같은 사전이 있는 경우:

es:
  books:
    index:
      title: "Título"

app/views/books/index.html.erb 템플릿 내부에서 books.index.title 값을 다음과 같이 조회할 수 있습니다(점 사용):

<%= t '.title' %>

참고: 부분별 자동 번역 범위 지정은 translate 뷰 헬퍼 메서드에서만 사용할 수 있습니다.

“게으른” 조회는 컨트롤러에서도 사용할 수 있습니다:

en:
  books:
    create:
      success: Book created!

이는 플래시 메시지를 설정하는 등에 유용합니다:

class BooksController < ApplicationController
  def create
    # ...
    redirect_to books_url, notice: t('.success')
  end
end

복수화

많은 언어 - 영어를 포함 - 에는 주어진 문자열에 대해 단수와 복수의 두 가지 형태만 있습니다. 예를 들어 “1 message"와 "2 messages"입니다. 다른 언어(아랍어, 일본어, 러시아어 등)에는 복수 형태가 추가되거나 더 적습니다. 따라서 I18n API는 유연한 복수화 기능을 제공합니다.

:count 보간 변수는 번역에 보간되고 복수화 백엔드에 정의된 복수화 규칙에 따라 번역을 선택하는 데 특별한 역할을 합니다. 기본적으로 영어 복수화 규칙만 적용됩니다.

I18n.backend.store_translations :en, inbox: {
  zero: 'no messages', # optional
  one: 'one message',
  other: '%{count} messages'
}
I18n.translate :inbox, count: 2
# => '2 messages'

I18n.translate :inbox, count: 1
# => 'one message'

I18n.translate :inbox, count: 0
# => 'no messages'

:en의 복수화 알고리즘은 다음과 같이 간단합니다:

lookup_key = :zero if count == 0 && entry.has_key?(:zero)
lookup_key ||= count == 1 ? :one : :other
entry[lookup_key]

:one로 표시된 번역은 단수로, :other는 복수로 간주됩니다. 카운트가 0이고 :zero 항목이 있는 경우 :other 대신 사용됩니다.

키 조회가 복수화에 적합한 해시를 반환하지 않으면 I18n::InvalidPluralizationData 예외가 발생합니다.

로케일 별 규칙

I18n 젬은 로케일별 규칙을 사용할 수 있는 Pluralization 백엔드를 제공합니다. 이를 Simple 백엔드에 포함하고 번역 저장소에 로컬화된 복수화 알고리즘을 i18n.plural.rule로 추가합니다.

I18n::Backend::Simple.include(I18n::Backend::Pluralization)
I18n.backend.store_translations :pt, i18n: { plural: { rule: lambda { |n| [0, 1].include?(n) ? :one : :other } } }
I18n.backend.store_translations :pt, apples: { one: 'one or none', other: 'more than one' }

I18n.t :apples, count: 0, locale: :pt
# => 'one or none'

또는 rails-i18n 별도의 젬을 사용하여 더 완전한 로케일별 복수화 규칙을 제공할 수 있습니다.

로케일 설정 및 전달

로케일은 I18n.locale에 의사-전역적으로 설정되거나(이는 Time.zone과 같은 방식으로 Thread.current를 사용합니다) #translate#localize에 옵션으로 전달될 수 있습니다.

로케일이 전달되지 않으면 I18n.locale이 사용됩니다:

I18n.locale = :de
I18n.t :foo
I18n.l Time.now

명시적으로 로케일 전달:

I18n.t :foo, locale: :de
I18n.l Time.now, locale: :de

I18n.locale은 기본적으로 I18n.default_locale(기본값: :en)로 설정됩니다. 기본 로케일은 다음과 같이 설정할 수 있습니다:

I18n.default_locale = :de

안전한 HTML 번역 사용

‘_html’ 접미사가 있는 키와 ‘html'이라는 이름의계속:

안전한 HTML 번역 사용

’_html’ 접미사가 있는 키와 ‘html'이라는 이름의 키는 HTML 안전으로 표시됩니다. 이를 뷰에서 사용하면 HTML이 이스케이프되지 않습니다.

# config/locales/en.yml
en:
  welcome: <b>welcome!</b>
  hello_html: <b>hello!</b>
  title:
    html: <b>title!</b>
<!-- app/views/home/index.html.erb -->
<div><%= t('welcome') %></div>
<div><%= raw t('welcome') %></div>
<div><%= t('hello_html') %></div>
<div><%= t('title.html') %></div>

보간은 필요한 경우 이스케이프됩니다. 예를 들어 다음과 같은 경우:

en:
  welcome_html: "<b>Welcome %{username}!</b>"

사용자가 설정한 사용자 이름을 안전하게 전달할 수 있습니다:

<%# 이것은 안전합니다. 필요한 경우 이스케이프됩니다. %>
<%= t('welcome_html', username: @current_user.username) %>

반면 안전한 문자열은 문자 그대로 보간됩니다.

참고: 번역 텍스트를 자동으로 HTML 안전으로 변환하는 기능은 translate(또는 t) 헬퍼 메서드에서만 사용할 수 있습니다. 이는 뷰와 컨트롤러에서 작동합니다.

i18n demo HTML safe

Active Record 모델에 대한 번역

Model.model_name.humanModel.human_attribute_name(attribute)를 사용하여 모델 및 속성 이름에 대한 번역을 투명하게 조회할 수 있습니다.

예를 들어 다음과 같은 번역을 추가하면:

en:
  activerecord:
    models:
      user: Customer
    attributes:
      user:
        login: "Handle"
      # User 속성 "login"을 "Handle"로 번역합니다.

그러면 User.model_name.human은 "Customer"를, User.human_attribute_name("login")은 "Handle"을 반환합니다.

모델 이름의 복수형도 설정할 수 있습니다. 다음과 같이 추가하면 됩니다:

en:
  activerecord:
    models:
      user:
        one: Customer
        other: Customers

그러면 User.model_name.human(count: 2)는 "Customers"를, User.model_name.human(count: 1) 또는 매개변수 없이는 "Customer"를 반환합니다.

주어진 모델 내의 중첩 속성에 액세스해야 하는 경우 모델 수준의 번역 파일에서 model/attribute 아래에 이를 중첩해야 합니다:

en:
  activerecord:
    attributes:
      user/role:
        admin: "Admin"
        contributor: "Contributor"

그러면 User.human_attribute_name("role.admin")은 "Admin"을 반환합니다.

참고: ActiveModel을 포함하고 ActiveRecord::Base를 상속하지 않는 클래스를 사용하는 경우 위의 키 경로에서 activerecordactivemodel로 바꾸세요.

오류 메시지 범위

Active Record 유효성 검사 오류 메시지도 쉽게 번역할 수 있습니다. Active Record는 모델, 속성 및/또는 유효성 검사에 대한 다른 메시지를 제공할 수 있도록 번역을 배치할 수 있는 몇 가지 네임스페이스를 제공합니다. 또한 단일 테이블 상속을 투명하게 고려합니다.

이를 통해 메시지를 애플리케이션의 요구 사항에 맞게 유연하게 조정할 수 있는 강력한 수단을 제공합니다.

다음과 같은 유효성 검사가 있는 User 모델을 고려해 보겠습니다:

class User < ApplicationRecord
  validates :name, presence: true
end

이 경우 오류 메시지의 키는 :blank입니다. 따라서 이 예에서는 다음 키를 순서대로 시도하고 첫 번째 결과를 반환합니다:

activerecord.errors.models.user.attributes.name.blank
activerecord.errors.models.user.blank
activerecord.errors.messages.blank
errors.attributes.name.blank
errors.messages.blank

더 추상적으로 설명하면 다음 목록의 첫 번째 일치하는 키를 반환합니다.

activerecord.errors.models.[model_name].attributes.[attribute_name].[key]
activerecord.errors.models.[model_name].[key]
activerecord.errors.messages.[key]
errors.attributes.[attribute_name].[key]
errors.messages.[key]

모델이 상속을 사용하는 경우 메시지는 상속 체인에서 조회됩니다.

예를 들어 Admin 모델이 User를 상속한다고 가정해 보겠습니다:

class Admin < User
  validates :name, presence: true
end

그러면 Active Record는 다음 순서로 메시지를 찾습니다:

activerecord.errors.models.admin.attributes.name.blank
activerecord.errors.models.admin.blank
activerecord.errors.models.user.attributes.name.blank
activerecord.errors.models.user.blank
activerecord.errors.messages.blank
errors.attributes.name.blank
errors.messages.blank

이렇게 하면 모델 상속 체인의 다른 지점에서 다양한 오류 메시지에 대한 특별한 번역을 제공할 수 있습니다.

오류 메시지 보간

번역된 모델 이름, 번역된 속성 이름 및 값은 각각 model, attributevalue로 보간할 수 있습니다.

따라서 기본 오류 메시지 "cannot be blank" 대신 다음과 같이 속성 이름을 사용할 수 있습니다: "Please fill in your %{attribute}".

  • count는 사용 가능한 경우 복수화에 사용할 수 있습니다:
유효성 검사 옵션 포함 메시지 보간
confirmation - :confirmation attribute
acceptance - :accepted -
presence - :blank -
absence - :present -
length :within, :in :too_short count
length :within, :in :too_long count
length :is :wrong_length count
length :minimum :too_short count
length :maximum :too_long count
uniqueness - :taken -
format - :invalid -
inclusion - :inclusion -
exclusion - :exclusion -
associated - :invalid -
non-optional association - :required -
numericality - :notanumber -
numericality :greater_than :greater_than count
numericality :greaterthanorequalto :greaterthanorequalto count
numericality :equal_to :equal_to count
numericality :less_than :less_than count
numericality :lessthanorequalto :lessthanorequalto count
numericality :other_than :other_than count
numericality :only_integer :notaninteger -
numericality :in :in count
numericality :odd :odd -
numericality :even :even -
comparison :greater_than :greater_than count
comparison :greaterthanorequalto :greaterthanorequalto count
comparison :equal_to :equal_to count
comparison :less_than :less_than count
comparison :lessthanorequalto :lessthanorequalto count
comparison :other_than :other_than count

Action Mailer 이메일 제목에 대한 번역

mail 메서드에 제목을 전달하지 않으면 Action Mailer가 번역에서 찾으려고 시도합니다. 수행되는 조회는 <mailer_scope>.<action_name>.subject 패턴을 사용하여 키를 구성합니다.

# user_mailer.rb
class UserMailer < ActionMailer::Base
  def welcome(user)
    #...
  end
end
en:
  user_mailer:
    welcome:
      subject: "Welcome to Rails Guides!"

보간 매개변수를 전송하려면 메일러에서 default_i18n_subject 메서드를 사용합니다.

# user_mailer.rb
class UserMailer < ActionMailer::Base
  def welcome(user)
    mail(to: user.email, subject: default_i18n_subject(user: user.name))
  end
end
en:
  user_mailer:
    welcome:
      subject: "%{user}, welcome to Rails Guides!"

국제화 지원을 제공하는 기타 기본 제공 메서드 개요

Rails는 고정 문자열 및 기타 지역화된 정보(예: 형식 문자열 및 기타 형식 정보)를 몇 가지 헬퍼에서 사용합니다. 간단한 개요는 다음과 같습니다.

Action View 헬퍼 메서드

  • distance_of_time_in_words는 결과를 번역하고 복수화하며 초, 분, 시간 등의 수를 보간합니다. datetime.distanceinwords 번역을 참조하세요.

  • datetime_selectselect_month는 결과 선택 태그를 채우기 위해 번역된 월 이름을 사용합니다. date.month_names의 번역을 참조하세요. datetime_select는 또한 date.order에서 순서 옵션을 조회합니다(명시적으로 옵션을 전달하지 않는 경우). 모든 날짜 선택 헬퍼는 datetime.prompts 범위의 번역을 사용하여 프롬프트를 번역합니다.

  • number_to_currency, number_with_precision, number_to_percentage, number_with_delimiternumber_to_human_size 헬퍼는 number 범위의 숫자 형식 설정을 사용합니다.

Active Model 메서드

  • model_name.humanhuman_attribute_nameactiverecord.models 범위에 있는 모델 이름 및 속성 이름 번역을 사용합니다. 또한 위의 "오류 메시지 범위"에서 설명한 대로 상속 클래스 이름에 대한 번역을 지원합니다.

  • ActiveModel::Errors#generate_message(Active Model 유효성 검사에서 사용되지만 수동으로도 사용할 수 있음)는 model_name.humanhuman_attribute_name(위 참조)을 사용합니다. 또한 오류 메시지를 번역하고 상속 클래스 이름에 대한 번역을 지원합니다.

  • ActiveModel::Error#full_messageActiveModel::Errors#full_messageserrors.format(기본값: "%{attribute} %{message}")에서 조회한 형식을 사용하여 속성 이름을 오류 메시지에 접두사로 추가합니다. 기본 형식을 앱의 로케일 파일에서 재정의할 수 계속:

  • ActiveModel::Error#full_messageActiveModel::Errors#full_messageserrors.format(기본값: "%{attribute} %{message}")에서 조회한 형식을 사용하여 속성 이름을 오류 메시지에 접두사로 추가합니다. 기본 형식을 앱의 로케일 파일에서 재정의할 수 있습니다. 모델 또는 속성별로 형식을 사용자 정의하려면 config.active_model.i18n_customize_full_message)를 참조하세요.

Active Support 메서드

  • Array#to_sentencesupport.array 범위에 있는 형식 설정을 사용합니다.

사용자 정의 번역 저장

Active Support와 함께 제공되는 Simple 백엔드를 사용하면 번역을 일반 Ruby와 YAML 형식으로 모두 저장할 수 있습니다.[^2]

예를 들어 번역을 제공하는 Ruby 해시는 다음과 같이 보일 수 있습니다:

{
  pt: {
    foo: {
      bar: "baz"
    }
  }
}

동등한 YAML 파일은 다음과 같습니다:

pt:
  foo:
    bar: baz

보시다시피 두 경우 모두 최상위 키는 로케일입니다. :foo는 네임스페이스 키이고 :bar는 "baz” 번역에 대한 키입니다.

Active Support en.yml 번역 YAML 파일의 “실제” 예는 다음과 같습니다:

en:
  date:
    formats:
      default: "%Y-%m-%d"
      short: "%b %d"
      long: "%B %d, %Y"

따라서 다음과 같은 모든 등가 조회는 :short 날짜 형식 "%b %d"를 반환합니다:

I18n.t 'date.formats.short'
I18n.t 'formats.short', scope: :date
I18n.t :short, scope: 'date.formats'
I18n.t :short, scope: [:date, :formats]

일반적으로 YAML을 번역 저장 형식으로 사용하는 것이 좋습니다. 그러나 때로는 로케일 데이터의 일부로 Ruby 람다를 저장하려는 경우가 있습니다. 예를 들어 특수 날짜 형식의 경우 등입니다.

I18n 설정 사용자 정의

다른 백엔드 사용

여러 가지 이유로 Active Support와 함께 제공되는 Simple 백엔드는 Ruby on Rails에 대해 “가능한 가장 단순한 작업"만 수행합니다.[^3] 즉, 영어와 영어와 매우 유사한 언어에 대해서만 보장됩니다. 또한 Simple 백엔드는 번역을 동적으로 저장할 수 없고 읽기만 할 수 있습니다.

그렇다고 해서 이러한 제한에 갇혀 있는 것은 아닙니다. Ruby I18n 젬은 I18n.backend= 세터를 통해 Simple 백엔드 구현을 다른 것으로 쉽게 교체할 수 있게 해줍니다.

예를 들어 Simple 백엔드를 Chain 백엔드로 대체하여 여러 백엔드를 체인할 수 있습니다. 이는 표준 번역을 Simple 백엔드와 함께 사용하고 사용자 정의 애플리케이션 번역을 데이터베이스 또는 다른 백엔드에 저장하려는 경우 유용합니다.

Chain 백엔드를 사용하면 Active Record 백엔드를 사용하고 (기본) Simple 백엔드로 폴백할 수 있습니다:

I18n.backend = I18n::Backend::Chain.new(I18n::Backend::ActiveRecord.new, I18n.backend)

다른 예외 처리기 사용

I18n API는 해당 예기치 않은 조건이 발생할 때 백엔드에서 발생시킬 다음과 같은 예외를 정의합니다:

예외 이유
I18n::MissingTranslationData 요청된 키에 대한 번역이 없습니다
I18n::InvalidLocale I18n.locale에 설정된 로케일이 잘못되었습니다(예: nil)
I18n::InvalidPluralizationData 카운트 옵션이 전달되었지만 번역 데이터가 복수화에 적합하지 않습니다
I18n::MissingInterpolationArgument 번역에 전달되지 않은 보간 인수가 필요합니다
I18n::ReservedInterpolationKey 번역에 예약된 보간 변수 이름(즉, scope, default 중 하나)이 포함되어 있습니다
I18n::UnknownFileType 백엔드가 I18n.load_path에 추가된 파일 유형을 처리하는 방법을 모릅니다

I18n::MissingTranslationData 처리 방식 사용자 정의

config.i18n.raise_on_missing_translationstrue이면 I18n::MissingTranslationData 오류가 발생합니다. 누락된 번역이 요청되는 곳을 캐치할 수 있도록 테스트 환경에서 이 옵션을 켜는 것이 좋습니다.

config.i18n.raise_on_missing_translationsfalse(모든 환경의 기본값)이면 예외의 오류 메시지가 인쇄됩니다. 이에는 누락된 키/범위가 포함되므로 코드를 수정할 수 있습니다.

이 동작을 더 사용자 정의하려면 config.i18n.raise_on_missing_translations = false로 설정하고 I18n.exception_handler를 구현해야 합니다. 사용자 정의 예외 처리기는 프로시저 또는 call 메서드가 있는 클래스일 수 있습니다:

# config/initializers/i18n.rb
module I18n
  class RaiseExceptForSpecificKeyExceptionHandler
    def call(exception, locale, key, options)
      if key == "special.key"
        "translation missing!" # 이것을 반환하고 발생시키지 마세요
      elsif exception.is_a?(MissingTranslation)
        raise exception.to_exception
      else
        raise exception
      end
    end
  end
end

I18n.exception_handler = I18n::RaiseExceptForSpecificKeyExceptionHandler.new

이렇게 하면 I18n.t("special.key")의 경우를 제외하고 기본 처리기와 동일한 방식으로 모든 예외가 발생합니다.

모델 콘텐츠 번역

이 가이드에서 설명한 I18n API는 주로 인터페이스 문자열을 번역하는 데 사용됩니다. 모델 콘텐츠(예: 블로그 게시물)를 번역하려면 다른 솔루션이 필요합니다.

이 작업을 돕는 여러 젬이 있습니다:

  • Mobility: 번역 테이블, JSON 열(PostgreSQL) 등 다양한 형식으로 번역을 저장할 수 있는 지원을 제공합니다.
  • Traco: 모델 테이블 자체에 저장된 번역 가능한 열

결론

이 시점에서 Ruby on Rails의 I18n 지원이 어떻게 작동하는지 잘 알고 있으며 프로젝트 번역을 시작할 준비가 되었습니다.

Rails I18n에 기여

Ruby on Rails의 I18n 지원은 2.2 릴리스에 도입되었으며 여전히 발전 중입니다. 이 프로젝트는 Ruby on Rails 개발의 좋은 전통을 따라 실제 애플리케이션에서 먼저 솔루션을 발전시키고 가장 널리 유용한 기능만 핵심에 포함시킵니다.

따라서 우리는 모든 사람이 젬이나 다른 라이브러리에서 새로운 아이디어와 기능을 실험하고 이를 커뮤니티에 공개하도록 권장합니다. (우리의 메일링 리스트에 발표하는 것을 잊지 마세요!)

Ruby on Rails에 대한 예제 번역 데이터 리포지토리에 귀하의 로케일(언어)이 누락된 경우 fork하고 데이터를 추가한 다음 pull request를 보내주세요.

리소스

  • Google 그룹: rails-i18n - 프로젝트의 메일링 리스트입니다.
  • GitHub: rails-i18n - rails-i18n 프로젝트의 코드 리포지토리 및 이슈 트래커. 가장 중요한 것은 대부분의 경우 애플리케이션에 작동할 수 있는 많은 예제 번역을 찾을 수 있다는 것입니다.
  • GitHub: i18n - i18n 젬의 코드 리포지토리 및 이슈 트래커.

저자

각주

[^1]: 또는 Wikipedia에서 인용하면: "국제화는 소프트웨어 애플리케이션을 설계하여 엔지니어링 변경 없이 다양한 언어와 지역에 적응할 수 있게 하는 프로세스입니다. 지역화는 로케일별 구성 요소를 추가하고 텍스트를 번역하여 특정 지역 또는 언어에 맞게 애플리케이션을 적응시키는 프로세스입니다.”

[^2]: 다른 백엔드는 다른 형식을 허용하거나 요구할 수 있습니다. 예를 들어 GetText 백엔드는 GetText 파일을 읽을 수 있습니다.

[^3]: 이러한 이유 중 하나는 국제화 기능이 필요하지 않은 애플리케이션에 대해 불필요한 부하를 발생시키지 않도록 I18n 라이브러리를 가능한 한 단순하게 유지해야 한다는 것입니다. 다른 이유는 모든 언어에 대한 모든 I18n 관련 문제를 한 번에 해결할 수 있는 솔루션을 구현하는 것이 사실상 불가능하다는 것입니다. 따라서 전체 구현을 쉽게 교체할 수 있는 솔루션이 적절합니다. 이렇게 하면 사용자 정의 기능 및 확장을 실험하기도 훨씬 쉽습니다.