aboutsummaryrefslogtreecommitdiffstats
path: root/tasks
diff options
context:
space:
mode:
authorToshiaki Asai <toshi.alternative@gmail.com>2016-05-17 07:41:13 +0900
committerToshiaki Asai <toshi.alternative@gmail.com>2016-05-17 07:41:13 +0900
commitaca34d63712e9e2660a4100aae15a2215f6c9072 (patch)
treea021594a67d8f32b4eb8f6c695cad37661914e8a /tasks
parent856e465a002eb7de485fbea0ff81cdd2638ab283 (diff)
downloadmikutter-aca34d63712e9e2660a4100aae15a2215f6c9072.tar.gz
Transifexに標準プラグインのpotファイルをアップロードするタスク
Diffstat (limited to 'tasks')
-rw-r--r--tasks/transifex.rake53
-rw-r--r--tasks/transifex.rb130
2 files changed, 183 insertions, 0 deletions
diff --git a/tasks/transifex.rake b/tasks/transifex.rake
new file mode 100644
index 00000000..e3d4808b
--- /dev/null
+++ b/tasks/transifex.rake
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+namespace 'transifex' do
+ task 'upload' do
+ require 'tmpdir'
+ require 'httpclient'
+ require 'json'
+ require 'pp'
+ require 'set'
+ require_relative '../core/boot/option'
+ require_relative '../core/miquire'
+ require_relative 'transifex'
+
+ miquire :boot, 'delayer'
+ miquire :core, "miquire_plugin"
+
+ project_name = ENV['TRANSIFEX_PROJECT_NAME']
+
+ Dir.mktmpdir('mikutter-transifex-upload') do |confroot|
+ Mopt.parse(["--confroot=#{confroot}"], exec_command: false)
+ project = Transifex.project_detail(project_name)
+ existing_resource_slugs = Set.new(project[:resources].map{|res|res[:slug].to_sym})
+ Miquire::Plugin.loadpath << Environment::PLUGIN_PATH << File.join(__dir__, "..", "plugin")
+ Miquire::Plugin.each_spec do |spec|
+ pot_path = File.join(spec[:path], 'po', "#{spec[:slug]}.pot")
+ next unless FileTest.exist?(pot_path)
+ slug = spec[:slug] == :settings ? 'settings-1' : spec[:slug]
+ if existing_resource_slugs.include? slug.to_sym
+ puts "Update #{slug}"
+ pp Transifex.resource_update(project_name: project_name,
+ slug: slug,
+ content: File.open(pot_path).map(&:chomp).reject{|l|
+ l == '"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"'
+ }.reject{|l|
+ l == '#, fuzzy'
+ }.join("\n")
+ )
+ else
+ puts "Create #{spec[:slug]}"
+ pp Transifex.resource_create(project_name: project_name,
+ slug: slug,
+ name: spec[:slug], # 表示名を日本語にすると外人が核ミサイルを撃ってくるかもしれない
+ content: File.open(pot_path).map(&:chomp).reject{|l|
+ l == '"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"'
+ }.reject{|l|
+ l == '#, fuzzy'
+ }.join("\n")
+ )
+ end
+ end
+ end
+ end
+end
+
diff --git a/tasks/transifex.rb b/tasks/transifex.rb
new file mode 100644
index 00000000..6c911aaf
--- /dev/null
+++ b/tasks/transifex.rb
@@ -0,0 +1,130 @@
+# -*- coding: utf-8 -*-
+
+=begin rdoc
+ Transifexと連携するためのユーティリティ
+=end
+module Transifex
+ extend self
+
+ SLUG_SIZE = 50
+ CONTENT_TYPE_MULTIPART_FORMDATA = 'multipart/form-data'
+ CONTENT_TYPE_APPLICATION_JSON = 'application/json'
+
+ # Transifexプロジェクトの情報を取得する
+ # ==== Args
+ # [project_name] String プロジェクト名
+ # ==== Return
+ # Hashプロジェクトの情報
+ def project_detail(project_name)
+ get_request("http://www.transifex.com/api/2/project/#{project_name}/?details")
+ end
+
+ # resource(mikutterの場合はpotファイル)をアップロードし、新しいResourceとして登録する。
+ # 既に同じslugを持つResourceは登録できない。代わりに、 Transifex.resource_update を使う
+ # ==== Args
+ # [project_name:] プロジェクト名
+ # [slug:] String アップロードするresourceのslug。プラグインスラッグを使用する。50文字まで
+ # [name:] String resourceの名前。プラグイン名を使用する。
+ # [i18n_type:] String 翻訳形式。省略するとPO。mikutterでは必ず省略する。
+ # [categories:] Array カテゴリ。いらん
+ # [priority:] Transifex::Priority 翻訳優先順位。
+ # [content:] IO|String resourceの内容。potファイルの中身のこと。IOを渡すとそれをreadした結果、Stringならその内容をそのままアップロードする
+ # ==== Return
+ # Hash レスポンス
+ # ==== See
+ # http://docs.transifex.com/api/resources/#uploading-and-downloading-resources
+ # ==== Raise
+ # SlugTooLongError slugが SLUG_SIZE 文字を超えている場合
+ def resource_create(project_name:, slug:, name:, i18n_type: 'PO', categories: [], priority: Priority::NORMAL, content:)
+ slug, name, priority = slug.to_s, name.to_s, priority.to_i
+ raise SlugTooLongError, "The current maximum value for the field slug is #{SLUG_SIZE} characters. http://docs.transifex.com/api/resources/#uploading-and-downloading-resources" if slug.size > SLUG_SIZE
+ if content.is_a? IO
+ content = content.read end
+ post_request("http://www.transifex.com/api/2/project/#{project_name}/resources/",
+ content_type: CONTENT_TYPE_APPLICATION_JSON,
+ params: {
+ slug: slug,
+ name: name,
+ i18n_type: i18n_type,
+ categories: categories,
+ priority: priority,
+ content: content
+ }
+ )
+ end
+
+ # resource(mikutterの場合はpotファイル)をアップロードし、同じslugを持つResourceを上書きする。
+ # 存在しないResourceは登録できない。代わりに、 Transifex.resource_create を使う
+ # ==== Args
+ # [project_name:] プロジェクト名
+ # [slug:] String アップロードするresourceのslug。プラグインスラッグを使用する。50文字まで
+ # [content:] IO|String resourceの内容。potファイルの中身のこと。IOを渡すとそれをreadした結果、Stringならその内容をそのままアップロードする
+ # ==== Return
+ # Hash レスポンス
+ # ==== See
+ # http://docs.transifex.com/api/resources/#uploading-and-downloading-translations-for-a-file
+ def resource_update(project_name:, slug:, content:)
+ slug = slug.to_s
+ if content.is_a? IO
+ content = content.read end
+ put_request("http://www.transifex.com/api/2/project/#{project_name}/resource/#{slug}/content/",
+ content_type: CONTENT_TYPE_APPLICATION_JSON,
+ params: {content: content}
+ )
+ end
+
+ def resource_get(project_name:, slug:)
+ slug = slug.to_s
+ get_request("http://www.transifex.com/api/2/project/#{project_name}/resource/#{slug}/content/")
+ end
+
+ private
+
+ def get_request(url)
+ clnt = HTTPClient.new
+ clnt.set_auth(url, ENV['TRANSIFEX_USER'], ENV['TRANSIFEX_PASSWORD'])
+ JSON.parse(clnt.get_content(url), symbolize_names: true)
+ end
+
+ def post_request(url, content_type: CONTENT_TYPE_MULTIPART_FORMDATA, params:)
+ clnt = HTTPClient.new
+ clnt.set_auth(url, ENV['TRANSIFEX_USER'], ENV['TRANSIFEX_PASSWORD'])
+ case content_type
+ when CONTENT_TYPE_MULTIPART_FORMDATA
+ content = params
+ when CONTENT_TYPE_APPLICATION_JSON
+ content = params.to_json
+ end
+ JSON.parse(clnt.post_content(url, content, 'Content-Type' => content_type), symbolize_names: true)
+ rescue HTTPClient::BadResponseError => err
+ pp err.res.content
+ end
+
+ def put_request(url, content_type: CONTENT_TYPE_MULTIPART_FORMDATA, params:)
+ clnt = HTTPClient.new
+ clnt.set_auth(url, ENV['TRANSIFEX_USER'], ENV['TRANSIFEX_PASSWORD'])
+ case content_type
+ when CONTENT_TYPE_MULTIPART_FORMDATA
+ content = params
+ when CONTENT_TYPE_APPLICATION_JSON
+ content = params.to_json
+ end
+ JSON.parse(clnt.__send__(:follow_redirect, :put, url, nil, content, 'Content-Type' => content_type).content, symbolize_names: true)
+ rescue HTTPClient::BadResponseError => err
+ pp err.res.content
+ end
+
+
+ class Priority
+ attr_reader :to_i
+ def initialize(prio)
+ @to_i = prio.to_i end
+
+ NORMAL = new(0)
+ HIGH = new(1)
+ URGENT = new(2)
+ end
+
+ class Error < RuntimeError; end
+ class SlugTooLongError < Error; end
+end