{"action":"created","comment":{"url":"https://api.github.com/repos/spoqa/spoqa.github.com/pulls/comments/140964883","pull_request_review_id":65109046,"id":140964883,"diff_hunk":"@@ -0,0 +1,193 @@\n+---\n+layout: entry\n+title: 아에이오우 튜토리얼\n+author: 최종찬\n+author-email: chan@spoqa.com\n+description: 다국어 스크립트 라이브러리인 아에이오우(aeiou)를 만들게 된 간단한 배경과 사용법에 대해서 알아봅니다.\n+publish: true\n+---\n+\n+이 글에서는 스포카 프론트엔드 프로젝트에서 사용하는 다국어 스크립트 라이브러리인\n+[아에이오우(aeiou)](https://github.com/spoqa/aeiou)를 만들게 된 간단한 배경과 이 스크립트의 사용법에 대해서 알아봅니다.\n+\n+## 배경\n+도도 포인트는 2017년 현재 한국과 일본에서 서비스되고 있으므로\n+점주와 엔드유저에게 노출되는 프론트엔드 코드는 일본어에 대한 고려가 돼있어야 합니다.\n+\n+예전부터 도도 포인트 프론트엔드 코드는 파이썬의 [babel](http://babel.pocoo.org/en/latest/index.html)\n+라이브러리가 제공하는 자바스크립트 extract 기능을 활용하여 다국어를 지원하고 있었습니다.\n+\n+작년에 프론트엔드 저장소가 백엔드 저장소와 분리되면서 파이썬(babel) 의존성을 제거하기 위해\n+gettext 호출을 긁는 스크립트를 자바스크립트로 작성하게 되었고,\n+최근 다국어 지원이 필요한 프론트엔드 프로젝트가 늘어나면서 이를 라이브러리로 분리하게 되어서\n+README에 링크도 추가할 겸 튜토리얼을 작성하게 됐습니다.\n+\n+## gettext\n+아에이오우는 [gettext 번역 시스템](https://en.wikipedia.org/wiki/Gettext)에 기반하여 만들어져있습니다.\n+\n+gettext 번역 시스템은 요약하자면 아래의 예시와 같이 생긴 코드를 실행할 때:\n+\n+```js\n+console.log(gettext('안녕하세요'));\n+```\n+\n+한국어 [로케일](https://ko.wikipedia.org/wiki/%EB%A1%9C%EC%BC%80%EC%9D%BC)에서는\n+'안녕하세요'가 출력되고, 일본어 로케일에서는 'こんにちは'가 출력되도록 만들어주는 시스템입니다.\n+\n+### 메시지 카탈로그\n+`gettext`는 본래의 문장(안녕하세요)과 번역된 문장(こんにちは) 짝의 목록을 담고있는 메시지 카탈로그를 필요로 합니다.\n+아스키 포맷으로 `.po`, 바이너리 포맷은 `.mo` 확장자를 갖는 파일이며,\n+메시지 카탈로그 파일은 로케일 단위(`ko_KR.po`, `ja.po`, ...)로 존재합니다.\n+\n+이러한 파일들은 전부 손으로 직접 작성할 수도 있겠지만, 보통은\n+\n+1. 소스코드에서 `gettext` 호출을 추출하는 도구(아에이오우)를 사용해서\n+2. PO 템플릿 파일을 생성하고(`.pot` 확장자를 가집니다),\n+3. 생성된 템플릿 파일을 로케일별로 복사해서 번역 문장을 채우는 방식으로 작업합니다.\n+\n+템플릿 파일은 확장자가 `.pot`이지만, `.po` 파일과 다른 점은 번역문이 전부 비어있다는 것 뿐이고, 포맷은 `.po` 파일과 완전히 동일합니다.\n+\n+### 런타임\n+아직은 아에이오우에 런타임을 만들어놓지 않아서 `gettext` 런타임을 제공하는 라이브러리가 따로 필요합니다.","path":"_posts/2017-09-26-aeiou-tutorial.md","position":52,"original_position":51,"commit_id":"bdce09d53005fa9f9b15e99e5ca179bd2b0772ec","original_commit_id":"5e976189142124586ed4af4f4c8660397230b9e6","user":{"login":"disjukr","id":690661,"avatar_url":"https://avatars0.githubusercontent.com/u/690661?v=4","gravatar_id":"","url":"https://api.github.com/users/disjukr","html_url":"https://github.com/disjukr","followers_url":"https://api.github.com/users/disjukr/followers","following_url":"https://api.github.com/users/disjukr/following{/other_user}","gists_url":"https://api.github.com/users/disjukr/gists{/gist_id}","starred_url":"https://api.github.com/users/disjukr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/disjukr/subscriptions","organizations_url":"https://api.github.com/users/disjukr/orgs","repos_url":"https://api.github.com/users/disjukr/repos","events_url":"https://api.github.com/users/disjukr/events{/privacy}","received_events_url":"https://api.github.com/users/disjukr/received_events","type":"User","site_admin":false},"body":"음 다시보니 일단 `## gettext` 헤딩 안쪽이라 gettext 는 생략해도 괜찮을 것 같기는 한데 `gettext` 런타임이 뭘 하는지 설명이 안되어있는게 문제인 거군요","created_at":"2017-09-26T06:12:58Z","updated_at":"2017-09-26T06:12:58Z","html_url":"https://github.com/spoqa/spoqa.github.com/pull/217#discussion_r140964883","pull_request_url":"https://api.github.com/repos/spoqa/spoqa.github.com/pulls/217","author_association":"OWNER","_links":{"self":{"href":"https://api.github.com/repos/spoqa/spoqa.github.com/pulls/comments/140964883"},"html":{"href":"https://github.com/spoqa/spoqa.github.com/pull/217#discussion_r140964883"},"pull_request":{"href":"https://api.github.com/repos/spoqa/spoqa.github.com/pulls/217"}},"in_reply_to_id":140959837},"pull_request":{"url":"https://api.github.com/repos/spoqa/spoqa.github.com/pulls/217","id":143039811,"html_url":"https://github.com/spoqa/spoqa.github.com/pull/217","diff_url":"https://github.com/spoqa/spoqa.github.com/pull/217.diff","patch_url":"https://github.com/spoqa/spoqa.github.com/pull/217.patch","issue_url":"https://api.github.com/repos/spoqa/spoqa.github.com/issues/217","number":217,"state":"open","locked":false,"title":"아에이오우 튜토리얼","user":{"login":"disjukr","id":690661,"avatar_url":"https://avatars0.githubusercontent.com/u/690661?v=4","gravatar_id":"","url":"https://api.github.com/users/disjukr","html_url":"https://github.com/disjukr","followers_url":"https://api.github.com/users/disjukr/followers","following_url":"https://api.github.com/users/disjukr/following{/other_user}","gists_url":"https://api.github.com/users/disjukr/gists{/gist_id}","starred_url":"https://api.github.com/users/disjukr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/disjukr/subscriptions","organizations_url":"https://api.github.com/users/disjukr/orgs","repos_url":"https://api.github.com/users/disjukr/repos","events_url":"https://api.github.com/users/disjukr/events{/privacy}","received_events_url":"https://api.github.com/users/disjukr/received_events","type":"User","site_admin":false},"body":"","created_at":"2017-09-26T05:12:39Z","updated_at":"2017-09-26T06:12:58Z","closed_at":null,"merged_at":null,"merge_commit_sha":"85d0367bd09753551154f0fc1ebf9dcc3340dd8e","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/spoqa/spoqa.github.com/pulls/217/commits","review_comments_url":"https://api.github.com/repos/spoqa/spoqa.github.com/pulls/217/comments","review_comment_url":"https://api.github.com/repos/spoqa/spoqa.github.com/pulls/comments{/number}","comments_url":"https://api.github.com/repos/spoqa/spoqa.github.com/issues/217/comments","statuses_url":"https://api.github.com/repos/spoqa/spoqa.github.com/statuses/bdce09d53005fa9f9b15e99e5ca179bd2b0772ec","head":{"label":"disjukr:aeiou","ref":"aeiou","sha":"bdce09d53005fa9f9b15e99e5ca179bd2b0772ec","user":{"login":"disjukr","id":690661,"avatar_url":"https://avatars0.githubusercontent.com/u/690661?v=4","gravatar_id":"","url":"https://api.github.com/users/disjukr","html_url":"https://github.com/disjukr","followers_url":"https://api.github.com/users/disjukr/followers","following_url":"https://api.github.com/users/disjukr/following{/other_user}","gists_url":"https://api.github.com/users/disjukr/gists{/gist_id}","starred_url":"https://api.github.com/users/disjukr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/disjukr/subscriptions","organizations_url":"https://api.github.com/users/disjukr/orgs","repos_url":"https://api.github.com/users/disjukr/repos","events_url":"https://api.github.com/users/disjukr/events{/privacy}","received_events_url":"https://api.github.com/users/disjukr/received_events","type":"User","site_admin":false},"repo":{"id":63400829,"name":"spoqa.github.com","full_name":"disjukr/spoqa.github.com","owner":{"login":"disjukr","id":690661,"avatar_url":"https://avatars0.githubusercontent.com/u/690661?v=4","gravatar_id":"","url":"https://api.github.com/users/disjukr","html_url":"https://github.com/disjukr","followers_url":"https://api.github.com/users/disjukr/followers","following_url":"https://api.github.com/users/disjukr/following{/other_user}","gists_url":"https://api.github.com/users/disjukr/gists{/gist_id}","starred_url":"https://api.github.com/users/disjukr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/disjukr/subscriptions","organizations_url":"https://api.github.com/users/disjukr/orgs","repos_url":"https://api.github.com/users/disjukr/repos","events_url":"https://api.github.com/users/disjukr/events{/privacy}","received_events_url":"https://api.github.com/users/disjukr/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/disjukr/spoqa.github.com","description":"Spoqa's dev team blog","fork":true,"url":"https://api.github.com/repos/disjukr/spoqa.github.com","forks_url":"https://api.github.com/repos/disjukr/spoqa.github.com/forks","keys_url":"https://api.github.com/repos/disjukr/spoqa.github.com/keys{/key_id}","collaborators_url":"https://api.github.com/repos/disjukr/spoqa.github.com/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/disjukr/spoqa.github.com/teams","hooks_url":"https://api.github.com/repos/disjukr/spoqa.github.com/hooks","issue_events_url":"https://api.github.com/repos/disjukr/spoqa.github.com/issues/events{/number}","events_url":"https://api.github.com/repos/disjukr/spoqa.github.com/events","assignees_url":"https://api.github.com/repos/disjukr/spoqa.github.com/assignees{/user}","branches_url":"https://api.github.com/repos/disjukr/spoqa.github.com/branches{/branch}","tags_url":"https://api.github.com/repos/disjukr/spoqa.github.com/tags","blobs_url":"https://api.github.com/repos/disjukr/spoqa.github.com/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/disjukr/spoqa.github.com/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/disjukr/spoqa.github.com/git/refs{/sha}","trees_url":"https://api.github.com/repos/disjukr/spoqa.github.com/git/trees{/sha}","statuses_url":"https://api.github.com/repos/disjukr/spoqa.github.com/statuses/{sha}","languages_url":"https://api.github.com/repos/disjukr/spoqa.github.com/languages","stargazers_url":"https://api.github.com/repos/disjukr/spoqa.github.com/stargazers","contributors_url":"https://api.github.com/repos/disjukr/spoqa.github.com/contributors","subscribers_url":"https://api.github.com/repos/disjukr/spoqa.github.com/subscribers","subscription_url":"https://api.github.com/repos/disjukr/spoqa.github.com/subscription","commits_url":"https://api.github.com/repos/disjukr/spoqa.github.com/commits{/sha}","git_commits_url":"https://api.github.com/repos/disjukr/spoqa.github.com/git/commits{/sha}","comments_url":"https://api.github.com/repos/disjukr/spoqa.github.com/comments{/number}","issue_comment_url":"https://api.github.com/repos/disjukr/spoqa.github.com/issues/comments{/number}","contents_url":"https://api.github.com/repos/disjukr/spoqa.github.com/contents/{+path}","compare_url":"https://api.github.com/repos/disjukr/spoqa.github.com/compare/{base}...{head}","merges_url":"https://api.github.com/repos/disjukr/spoqa.github.com/merges","archive_url":"https://api.github.com/repos/disjukr/spoqa.github.com/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/disjukr/spoqa.github.com/downloads","issues_url":"https://api.github.com/repos/disjukr/spoqa.github.com/issues{/number}","pulls_url":"https://api.github.com/repos/disjukr/spoqa.github.com/pulls{/number}","milestones_url":"https://api.github.com/repos/disjukr/spoqa.github.com/milestones{/number}","notifications_url":"https://api.github.com/repos/disjukr/spoqa.github.com/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/disjukr/spoqa.github.com/labels{/name}","releases_url":"https://api.github.com/repos/disjukr/spoqa.github.com/releases{/id}","deployments_url":"https://api.github.com/repos/disjukr/spoqa.github.com/deployments","created_at":"2016-07-15T07:22:36Z","updated_at":"2017-01-18T03:02:04Z","pushed_at":"2017-09-26T06:11:08Z","git_url":"git://github.com/disjukr/spoqa.github.com.git","ssh_url":"git@github.com:disjukr/spoqa.github.com.git","clone_url":"https://github.com/disjukr/spoqa.github.com.git","svn_url":"https://github.com/disjukr/spoqa.github.com","homepage":"http://spoqa.github.io/","size":93354,"stargazers_count":1,"watchers_count":1,"language":"HTML","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":1,"default_branch":"master"}},"base":{"label":"spoqa:master","ref":"master","sha":"de663d67a1e22e7318b1a369d423d645c75457cb","user":{"login":"spoqa","id":785135,"avatar_url":"https://avatars0.githubusercontent.com/u/785135?v=4","gravatar_id":"","url":"https://api.github.com/users/spoqa","html_url":"https://github.com/spoqa","followers_url":"https://api.github.com/users/spoqa/followers","following_url":"https://api.github.com/users/spoqa/following{/other_user}","gists_url":"https://api.github.com/users/spoqa/gists{/gist_id}","starred_url":"https://api.github.com/users/spoqa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/spoqa/subscriptions","organizations_url":"https://api.github.com/users/spoqa/orgs","repos_url":"https://api.github.com/users/spoqa/repos","events_url":"https://api.github.com/users/spoqa/events{/privacy}","received_events_url":"https://api.github.com/users/spoqa/received_events","type":"Organization","site_admin":false},"repo":{"id":2861898,"name":"spoqa.github.com","full_name":"spoqa/spoqa.github.com","owner":{"login":"spoqa","id":785135,"avatar_url":"https://avatars0.githubusercontent.com/u/785135?v=4","gravatar_id":"","url":"https://api.github.com/users/spoqa","html_url":"https://github.com/spoqa","followers_url":"https://api.github.com/users/spoqa/followers","following_url":"https://api.github.com/users/spoqa/following{/other_user}","gists_url":"https://api.github.com/users/spoqa/gists{/gist_id}","starred_url":"https://api.github.com/users/spoqa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/spoqa/subscriptions","organizations_url":"https://api.github.com/users/spoqa/orgs","repos_url":"https://api.github.com/users/spoqa/repos","events_url":"https://api.github.com/users/spoqa/events{/privacy}","received_events_url":"https://api.github.com/users/spoqa/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/spoqa/spoqa.github.com","description":"Spoqa's dev team blog","fork":false,"url":"https://api.github.com/repos/spoqa/spoqa.github.com","forks_url":"https://api.github.com/repos/spoqa/spoqa.github.com/forks","keys_url":"https://api.github.com/repos/spoqa/spoqa.github.com/keys{/key_id}","collaborators_url":"https://api.github.com/repos/spoqa/spoqa.github.com/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/spoqa/spoqa.github.com/teams","hooks_url":"https://api.github.com/repos/spoqa/spoqa.github.com/hooks","issue_events_url":"https://api.github.com/repos/spoqa/spoqa.github.com/issues/events{/number}","events_url":"https://api.github.com/repos/spoqa/spoqa.github.com/events","assignees_url":"https://api.github.com/repos/spoqa/spoqa.github.com/assignees{/user}","branches_url":"https://api.github.com/repos/spoqa/spoqa.github.com/branches{/branch}","tags_url":"https://api.github.com/repos/spoqa/spoqa.github.com/tags","blobs_url":"https://api.github.com/repos/spoqa/spoqa.github.com/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/spoqa/spoqa.github.com/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/spoqa/spoqa.github.com/git/refs{/sha}","trees_url":"https://api.github.com/repos/spoqa/spoqa.github.com/git/trees{/sha}","statuses_url":"https://api.github.com/repos/spoqa/spoqa.github.com/statuses/{sha}","languages_url":"https://api.github.com/repos/spoqa/spoqa.github.com/languages","stargazers_url":"https://api.github.com/repos/spoqa/spoqa.github.com/stargazers","contributors_url":"https://api.github.com/repos/spoqa/spoqa.github.com/contributors","subscribers_url":"https://api.github.com/repos/spoqa/spoqa.github.com/subscribers","subscription_url":"https://api.github.com/repos/spoqa/spoqa.github.com/subscription","commits_url":"https://api.github.com/repos/spoqa/spoqa.github.com/commits{/sha}","git_commits_url":"https://api.github.com/repos/spoqa/spoqa.github.com/git/commits{/sha}","comments_url":"https://api.github.com/repos/spoqa/spoqa.github.com/comments{/number}","issue_comment_url":"https://api.github.com/repos/spoqa/spoqa.github.com/issues/comments{/number}","contents_url":"https://api.github.com/repos/spoqa/spoqa.github.com/contents/{+path}","compare_url":"https://api.github.com/repos/spoqa/spoqa.github.com/compare/{base}...{head}","merges_url":"https://api.github.com/repos/spoqa/spoqa.github.com/merges","archive_url":"https://api.github.com/repos/spoqa/spoqa.github.com/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/spoqa/spoqa.github.com/downloads","issues_url":"https://api.github.com/repos/spoqa/spoqa.github.com/issues{/number}","pulls_url":"https://api.github.com/repos/spoqa/spoqa.github.com/pulls{/number}","milestones_url":"https://api.github.com/repos/spoqa/spoqa.github.com/milestones{/number}","notifications_url":"https://api.github.com/repos/spoqa/spoqa.github.com/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/spoqa/spoqa.github.com/labels{/name}","releases_url":"https://api.github.com/repos/spoqa/spoqa.github.com/releases{/id}","deployments_url":"https://api.github.com/repos/spoqa/spoqa.github.com/deployments","created_at":"2011-11-27T17:21:35Z","updated_at":"2017-09-16T02:17:22Z","pushed_at":"2017-09-26T06:11:09Z","git_url":"git://github.com/spoqa/spoqa.github.com.git","ssh_url":"git@github.com:spoqa/spoqa.github.com.git","clone_url":"https://github.com/spoqa/spoqa.github.com.git","svn_url":"https://github.com/spoqa/spoqa.github.com","homepage":"https://spoqa.github.io/","size":92739,"stargazers_count":46,"watchers_count":46,"language":"HTML","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":61,"mirror_url":null,"open_issues_count":4,"forks":61,"open_issues":4,"watchers":46,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/spoqa/spoqa.github.com/pulls/217"},"html":{"href":"https://github.com/spoqa/spoqa.github.com/pull/217"},"issue":{"href":"https://api.github.com/repos/spoqa/spoqa.github.com/issues/217"},"comments":{"href":"https://api.github.com/repos/spoqa/spoqa.github.com/issues/217/comments"},"review_comments":{"href":"https://api.github.com/repos/spoqa/spoqa.github.com/pulls/217/comments"},"review_comment":{"href":"https://api.github.com/repos/spoqa/spoqa.github.com/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/spoqa/spoqa.github.com/pulls/217/commits"},"statuses":{"href":"https://api.github.com/repos/spoqa/spoqa.github.com/statuses/bdce09d53005fa9f9b15e99e5ca179bd2b0772ec"}},"author_association":"OWNER"}}
{"actor":{"display_login":"disjukr"}}