Ruby on Rails - full_messages 한국어 처리 | Ruby on Rails - full_messages for Korean

이 글은 액티브 레코드를 검증할 때 제공하는 문구를 한국어로 바꾸는 방법에 대한 내용입니다.

먼저 진행을 위해 예제 프로젝트를 만듭니다.

$ rails new example
$ cd example

간단하게 로그인 아이디, 이메일 필드를 갖는 사용자 모델을 만듭니다.

$ rails g scaffold user login:string email:string
$ rake db:migrate

app/models/user.rb

class User < ActiveRecord::Base
  validates :login, :presence   => true,
                    :uniqueness => true,
                    :length     => {:in => 3..20}

  validates :email, :presence   => true,
                    :uniqueness => true
end

여기까지 코드를 적고 서버를 올린 후 필드를 채우지 않고 새 사용자를 만들어 봅니다.

화면에 나오는 오류 문구는 ActiveModel::Errors#full_messages를 이용해서 만들어집니다.

app/views/users/_form.html.erb

<% @user.errors.full_messages.each do |msg| %>
  <li><%= msg %></li>
<% end %>

이제 한국어 사용을 위해 아래와 같이 설정하고 서버를 다시 올립니다.

config/application.rb

config.i18n.default_locale = :ko

한국어 문구를 위해 새로 파일을 작성합니다.

config/locales/ko.yml

ko:
  attributes:
    login: 아이디
    email: 이메일
  errors:
    messages:
      blank: 에 내용을 입력해 주세요

레일즈에서 기본적으로 제공하는 문구

위 영문에 대응하는 한국어 문구를 작성하면 됩니다.

문제

한국어 문구를 보여줬을 때 문제점이 몇 가지 있습니다.

필드 이름과 오류 문구 사이의 공백

이 공백은 activemodel/lib/active_model/locale/en.yml 파일에 errors.format 값이 “%{attribute} %{message}“로 설정되어 있기 때문에 생깁니다.

받침에 따른 조사

한국어는 체언의 받침 유무에 따라서 조사가 달라지는 경우가 많습니다. “이/가, 은/는, 을/를, 과/와” 등이 예가 되겠습니다.

필드 이름의 위치

위에서 얘기한 것처럼 errors.format 값이 “%{attribute} %{message}“이기 때문에 주어나 목적어가 반드시 처음에 나와야 합니다. 그래서 “다른 사람이 쓰고 있는 아이디입니다.” 형태의 문장을 만들 수 없습니다.

구현

위 문제를 모두 고치기 위해 아래와 같은 방법을 생각했습니다.

  1. errors.format 값을 %{message}로 바꿉니다.
  2. activerecord.errors.messages 안의 각 문구 안에 %{attribute}를 적절한 위치에 넣습니다.
  3. 문구 안에 조사를 같이 넣어줍니다.
  4. 체언에 따라 조사를 바꿉니다.

config/locales/ko.yml

문구에 조사를 구분하기 위해서 괄호 두 개로 감싸줍니다. 받침이 있는 형태이든 없는 형태이든 상관없습니다.

ko:
  attributes:
    login: 아이디
    email: 이메일
  errors:
    format: %{message}
    messages:
      blank: 헉! %{attribute}((을)) 입력해 주세요

레일즈 오류 문구 검색 순서

특정 모델 또는 특정 필드에 다른 문구를 보여 주려면 적절하게 설정하면 됩니다.

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

한국어 처리를 위해 새 파일을 작성합니다.

config/initializers/korean_full_messages.rb

# encoding: utf-8

class Korean
  # 받침에 따른 알맞은 조사를 구한다.
  PROPOSITIONS = {'이' => '가', '은' => '는', '을' => '를', '과' => '와'}

  def self.get_proposition word, proposition
    # 한국어만 처리한다.
    return '' if word.size == word.bytesize

    # 받침이 없을 때
    if word.mb_chars.last.decompose[2].nil?
      PROPOSITIONS[proposition] || proposition
    # 받침이 있을 때
    else
      PROPOSITIONS.invert[proposition] || proposition
    end
  end
end

module ActiveModel
  class Errors
    def korean_full_messages
      # 한국어 설정이 아니면 full_messages를 돌려준다.
      return full_messages unless I18n.locale == :ko

      full_messages.map do |message|
        # 오류 문구에서 ((조사)) 형태를 찾아 받침에 맞는 조사로 바꿔 준다.
        message.gsub(/(?<=(.{1}))\(\(([이가은는을를과와])\)\)/) do
          Korean.get_proposition $1, $2
        end
      end
    end
  end
end

app/views/users/_form.html.erb

  <% @user.errors.korean_full_messages.each do |msg| %>
    <li><%= msg %></li>
  <% end %>

참고