jp_quest 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.licensed.yml +10 -0
- data/.rspec +3 -0
- data/.rubocop.yml +49 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +39 -0
- data/dist/Gemfile +3 -0
- data/dist/example.rb +8 -0
- data/dist/start.bat +4 -0
- data/lib/jp_quest/error.rb +35 -0
- data/lib/jp_quest/extractor/description.rb +112 -0
- data/lib/jp_quest/extractor/subtitle.rb +26 -0
- data/lib/jp_quest/extractor/title.rb +26 -0
- data/lib/jp_quest/formatter.rb +159 -0
- data/lib/jp_quest/help.rb +130 -0
- data/lib/jp_quest/indent_helper.rb +36 -0
- data/lib/jp_quest/performer.rb +74 -0
- data/lib/jp_quest/reader.rb +107 -0
- data/lib/jp_quest/version.rb +5 -0
- data/lib/jp_quest/writer.rb +71 -0
- data/lib/jp_quest.rb +43 -0
- data/rake_helper.rb +29 -0
- data/sig/jp_quest.rbs +4 -0
- metadata +85 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 897794dabb7c1b722d1bcad7235c64e04c2ca449060278982774c7bcefc5f824
|
4
|
+
data.tar.gz: baaf02d4c32266a22178db399701b1b2bf5e0512401120e1a5a551de8fecfafd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 57396c508bc82648d1f18427e09445a7c8e82edcf21a4376b086c6fbea3845576907c6e268c09a37d084f3efaf908503b763887f0d22838e38dc9619c54e950a
|
7
|
+
data.tar.gz: 2e573574cf3731f8aefe7567aa57bc1fcc43b0b75fedc74f81455e4f1cc50dfdbb6168a62f1a1d2f6ae1e93e25e6368bcb936274dcc3522a0a33c418bf810c5d
|
data/.licensed.yml
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 3.0
|
3
|
+
NewCops: enable
|
4
|
+
Exclude:
|
5
|
+
- "bin/**/*"
|
6
|
+
|
7
|
+
Style/StringLiterals:
|
8
|
+
EnforcedStyle: double_quotes
|
9
|
+
|
10
|
+
Style/StringLiteralsInInterpolation:
|
11
|
+
EnforcedStyle: double_quotes
|
12
|
+
|
13
|
+
Style/Documentation:
|
14
|
+
Enabled: false
|
15
|
+
|
16
|
+
Style/ParallelAssignment:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
Metrics/MethodLength:
|
20
|
+
CountComments: true
|
21
|
+
Max: 20
|
22
|
+
|
23
|
+
Lint/ScriptPermission:
|
24
|
+
Enabled: false
|
25
|
+
|
26
|
+
Style/FetchEnvVar:
|
27
|
+
Enabled: false
|
28
|
+
|
29
|
+
RSpec/ExampleLength:
|
30
|
+
Max: 10
|
31
|
+
|
32
|
+
Style/FrozenStringLiteralComment:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
Lint/EmptyFile:
|
36
|
+
Enabled: false
|
37
|
+
|
38
|
+
RSpec/BeNil:
|
39
|
+
Enabled: false
|
40
|
+
|
41
|
+
Style/RaiseArgs:
|
42
|
+
Enabled: false
|
43
|
+
|
44
|
+
Style/WhileUntilModifier:
|
45
|
+
Enabled: false
|
46
|
+
|
47
|
+
require:
|
48
|
+
- rubocop-rake
|
49
|
+
- rubocop-rspec
|
data/CHANGELOG.md
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2024 milkeclair
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
## JpQuest
|
2
|
+
|
3
|
+
Translator for `.snbt` files. (title, subtitle, description)
|
4
|
+
If you want to translate to other languages than Japanese,
|
5
|
+
please add the `exchange_language` option during initialization.
|
6
|
+
Can always get help with `JpQuest.help`
|
7
|
+
|
8
|
+
#### Example
|
9
|
+
|
10
|
+
`JpQuest::Performer.new(exchange_language: "English")`
|
11
|
+
|
12
|
+
## Steps
|
13
|
+
|
14
|
+
1. Download [release](https://github.com/milkeclair/jp_quest/releases)
|
15
|
+
2. Make `.env` file
|
16
|
+
3. Add `OPENAI_API_KEY=your_api_key` to `.env`
|
17
|
+
4. Optional: Add `OPENAI_MODEL=some_openai_model` to `.env` **(default: gpt-4o-mini)**
|
18
|
+
5. Add `some.snbt` to `quests` directory
|
19
|
+
6. Check `output` directory
|
20
|
+
|
21
|
+
## Initialize Options
|
22
|
+
|
23
|
+
#### output_logs
|
24
|
+
|
25
|
+
Want to output OpenAI usage logs?
|
26
|
+
**(default: true)**
|
27
|
+
|
28
|
+
#### except_words
|
29
|
+
|
30
|
+
Words that you don't want to translate
|
31
|
+
**(default: empty array)**
|
32
|
+
|
33
|
+
#### exchange_language
|
34
|
+
|
35
|
+
Which language do you want to translate to?
|
36
|
+
**(default: japanese)**
|
37
|
+
|
38
|
+
#### display_help
|
39
|
+
|
40
|
+
Want to display help?
|
41
|
+
**(default: true)**
|
data/Rakefile
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rspec/core/rake_task"
|
5
|
+
require "rubocop/rake_task"
|
6
|
+
require "yard"
|
7
|
+
require_relative "rake_helper"
|
8
|
+
|
9
|
+
desc "analysis"
|
10
|
+
task :analysis do
|
11
|
+
sh "bundle install"
|
12
|
+
|
13
|
+
RakeHelper.init_rake_tasks
|
14
|
+
|
15
|
+
puts "--- rspec ---"
|
16
|
+
Rake::Task[:spec].invoke
|
17
|
+
|
18
|
+
puts "--- rubocop ---"
|
19
|
+
Rake::Task[:rubocop].invoke
|
20
|
+
|
21
|
+
puts "--- yard ---"
|
22
|
+
Rake::Task[:yard].invoke
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "push to github packages and rubygems"
|
26
|
+
task :push do
|
27
|
+
sh "bundle install"
|
28
|
+
|
29
|
+
puts "--- build ---"
|
30
|
+
RakeHelper.build_gem
|
31
|
+
|
32
|
+
puts "--- push to github packages ---"
|
33
|
+
RakeHelper.push_to_github_packages
|
34
|
+
|
35
|
+
puts "--- push to rubygems ---"
|
36
|
+
RakeHelper.push_to_rubygems
|
37
|
+
end
|
38
|
+
|
39
|
+
task default: :analysis
|
data/dist/Gemfile
ADDED
data/dist/example.rb
ADDED
data/dist/start.bat
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
module JpQuest
|
2
|
+
# 基底のエラークラス
|
3
|
+
class Error < StandardError; end
|
4
|
+
|
5
|
+
# パスが見つからない場合のエラークラス
|
6
|
+
class PathNotFoundError < Error
|
7
|
+
# ヒアドキュメントを使うと、先頭と末尾に空行が入る
|
8
|
+
# エラーメッセージも変更しやすいのでこうしている
|
9
|
+
DOES_NOT_EXIST = <<~TEXT.freeze
|
10
|
+
\n
|
11
|
+
Path does not exist: %s
|
12
|
+
TEXT
|
13
|
+
|
14
|
+
# @param [String] path パス
|
15
|
+
# @return [JpQuest::PathNotFoundError]
|
16
|
+
def initialize(path)
|
17
|
+
super(format(DOES_NOT_EXIST, path))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# 行数が異なる場合のエラークラス
|
22
|
+
class InvalidLineCountError < Error
|
23
|
+
INVALID_LINE_COUNT = <<~TEXT.freeze
|
24
|
+
\n
|
25
|
+
Invalid line count: %s
|
26
|
+
TEXT
|
27
|
+
|
28
|
+
# @param [Integer] expect_count 期待する行数
|
29
|
+
# @param [Integer] actual_count 実際の行数
|
30
|
+
# @return [JpQuest::InvalidLineCountError]
|
31
|
+
def initialize(expect_count, actual_count)
|
32
|
+
super(format(INVALID_LINE_COUNT, "Expected: #{expect_count}, Actual: #{actual_count}"))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module JpQuest
|
2
|
+
# SNBT形式のファイルからdescription: ["some description"]を抽出するモジュール
|
3
|
+
module DescriptionExtractor
|
4
|
+
# description: ["some description"]を抽出する
|
5
|
+
#
|
6
|
+
# @param [String] file_path ファイルのパス
|
7
|
+
# @return [Array<Hash>] 説明、開始行番号、終了行番号の配列
|
8
|
+
def extract_descriptions(file_path)
|
9
|
+
lines = File.readlines(file_path)
|
10
|
+
extract_from_file(lines)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
# ファイルから説明を抽出する
|
16
|
+
#
|
17
|
+
# @param [Array<String>] lines 行の配列
|
18
|
+
# @return [Array<Hash>] 説明、開始行番号、終了行番号、インデントのハッシュの配列
|
19
|
+
def extract_from_file(lines)
|
20
|
+
descs = []
|
21
|
+
desc_content = []
|
22
|
+
start_line = nil
|
23
|
+
|
24
|
+
lines.each_with_index do |line, index|
|
25
|
+
indent = count_indent(line)
|
26
|
+
|
27
|
+
# 1行の説明の場合はそのままハッシュに変換
|
28
|
+
# 複数行の場合は、開始行と終了行の間の説明を抽出する
|
29
|
+
if oneline?(line)
|
30
|
+
descs << build_oneline(line, index, indent)
|
31
|
+
elsif start_line?(line)
|
32
|
+
start_line = index
|
33
|
+
elsif middle_line?(line, start_line)
|
34
|
+
desc_content << line.strip
|
35
|
+
elsif end_line?(line, start_line)
|
36
|
+
descs << build_multiline(desc_content, start_line, index, indent)
|
37
|
+
start_line = nil
|
38
|
+
desc_content = []
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
descs
|
43
|
+
end
|
44
|
+
|
45
|
+
# 1行かどうか
|
46
|
+
#
|
47
|
+
# @param [String] line 行
|
48
|
+
# @return [Boolean]
|
49
|
+
def oneline?(line)
|
50
|
+
oneline_description?(line)
|
51
|
+
end
|
52
|
+
|
53
|
+
# 開始行かどうか
|
54
|
+
#
|
55
|
+
# @param [String] line 行
|
56
|
+
# @return [Boolean]
|
57
|
+
def start_line?(line)
|
58
|
+
start_of?(line, key: :description)
|
59
|
+
end
|
60
|
+
|
61
|
+
# 終了行かどうか
|
62
|
+
#
|
63
|
+
# @param [String] line 行
|
64
|
+
# @param [Integer] start_line 開始行番号
|
65
|
+
# @return [Boolean]
|
66
|
+
def end_line?(line, start_line)
|
67
|
+
line.strip.end_with?("]") && start_line
|
68
|
+
end
|
69
|
+
|
70
|
+
# 中間行かどうか
|
71
|
+
#
|
72
|
+
# @param [String] line 行
|
73
|
+
# @param [Integer] start_line 開始行番号
|
74
|
+
# @return [Boolean]
|
75
|
+
def middle_line?(line, start_line)
|
76
|
+
line.strip != "]" && start_line
|
77
|
+
end
|
78
|
+
|
79
|
+
# 1行の処理
|
80
|
+
#
|
81
|
+
# @param [String] line 行
|
82
|
+
# @param [Integer] index 行番号
|
83
|
+
# @param [Integer] indent インデント
|
84
|
+
# @return [Hash] 説明、開始行番号、終了行番号、インデントのハッシュ
|
85
|
+
def build_oneline(line, index, indent)
|
86
|
+
{
|
87
|
+
type: :description,
|
88
|
+
text: extract_oneline(line, is_desc: true),
|
89
|
+
start_line: index,
|
90
|
+
end_line: index,
|
91
|
+
indent: indent
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
# 複数行の処理
|
96
|
+
#
|
97
|
+
# @param [Array<String>] content 説明の配列
|
98
|
+
# @param [Integer] start_line 開始行番号
|
99
|
+
# @param [Integer] index 行番号
|
100
|
+
# @param [Integer] indent インデント
|
101
|
+
# @return [Hash] 説明、開始行番号、終了行番号、インデントのハッシュ
|
102
|
+
def build_multiline(content, start_line, index, indent)
|
103
|
+
{
|
104
|
+
type: :description,
|
105
|
+
text: content.join("\n"),
|
106
|
+
start_line: start_line,
|
107
|
+
end_line: index,
|
108
|
+
indent: indent
|
109
|
+
}
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module JpQuest
|
2
|
+
# SNBT形式のファイルからsubtitle: "some subtitle"を抽出するモジュール
|
3
|
+
module SubtitleExtractor
|
4
|
+
# subtitle: "some subtitle"を抽出する
|
5
|
+
#
|
6
|
+
# @param [String] file_path ファイルのパス
|
7
|
+
# @return [Array<Hash>] サブタイトルと行番号の配列
|
8
|
+
def extract_subtitles(file_path)
|
9
|
+
subtitles = []
|
10
|
+
lines = File.readlines(file_path)
|
11
|
+
lines.each_with_index do |line, index|
|
12
|
+
next unless start_of?(line, key: :subtitle)
|
13
|
+
|
14
|
+
subtitles << {
|
15
|
+
type: :subtitle,
|
16
|
+
text: extract_oneline(line),
|
17
|
+
start_line: index,
|
18
|
+
end_line: index,
|
19
|
+
indent: count_indent(line)
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
subtitles
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module JpQuest
|
2
|
+
# SNBT形式のファイルからtitle: "some title"を抽出するモジュール
|
3
|
+
module TitleExtractor
|
4
|
+
# title: "some title"を抽出する
|
5
|
+
#
|
6
|
+
# @param [String] file_path ファイルのパス
|
7
|
+
# @return [Array<Hash>] タイトルと行番号の配列
|
8
|
+
def extract_titles(file_path)
|
9
|
+
titles = []
|
10
|
+
lines = File.readlines(file_path)
|
11
|
+
lines.each_with_index do |line, index|
|
12
|
+
next unless start_of?(line, key: :title)
|
13
|
+
|
14
|
+
titles << {
|
15
|
+
type: :title,
|
16
|
+
text: extract_oneline(line),
|
17
|
+
start_line: index,
|
18
|
+
end_line: index,
|
19
|
+
indent: count_indent(line)
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
titles
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
require_relative "indent_helper"
|
2
|
+
|
3
|
+
module JpQuest
|
4
|
+
# 翻訳された内容をSNBT形式に整形するクラス
|
5
|
+
class Formatter
|
6
|
+
include IndentHelper
|
7
|
+
|
8
|
+
# 保存できるように整形
|
9
|
+
#
|
10
|
+
# @param [Hash] content コンテンツ
|
11
|
+
# @param [String] indent インデント
|
12
|
+
# @return [String] SNBT形式に整形したコンテンツ
|
13
|
+
def format_overwritable_lines(content, indent)
|
14
|
+
mid_indent = middle_indent(content[:indent])
|
15
|
+
indented_lines = add_indent_for_middle_lines(content, mid_indent)
|
16
|
+
formatted_lines = add_missing_lines(indented_lines, content, mid_indent)
|
17
|
+
format_for_snbt(formatted_lines, indent, content[:type])
|
18
|
+
end
|
19
|
+
|
20
|
+
# SNBT形式に整形
|
21
|
+
#
|
22
|
+
# @param [Array<String>] lines 行
|
23
|
+
# @param [String] indent インデント
|
24
|
+
# @param [Symbol] type コンテンツの種類
|
25
|
+
# @return [String] SNBT形式に整形した行
|
26
|
+
def format_for_snbt(lines, indent, type)
|
27
|
+
lines.map! { |line| delete_quotes(line) }
|
28
|
+
lines.map!(&:strip) unless type == :description
|
29
|
+
|
30
|
+
formatted_lines =
|
31
|
+
if lines.length == 1
|
32
|
+
type == :description ? "[#{lines[0].strip}]" : lines[0].strip.to_s
|
33
|
+
else
|
34
|
+
# description: [
|
35
|
+
# "Hello"
|
36
|
+
# "World"
|
37
|
+
# ]
|
38
|
+
"[\n#{lines.join("\n")}\n#{indent}]"
|
39
|
+
end
|
40
|
+
|
41
|
+
# " description: ["hoge"]"のような形式にする
|
42
|
+
"#{indent}#{type}: #{formatted_lines}"
|
43
|
+
end
|
44
|
+
|
45
|
+
# 不足している行を追加
|
46
|
+
#
|
47
|
+
# @param [Array<String>] lines 行
|
48
|
+
# @param [Hash] content コンテンツ
|
49
|
+
# @param [String] middle_indent 中間行のインデント
|
50
|
+
# @return [void]
|
51
|
+
def add_missing_lines(lines, content, middle_indent)
|
52
|
+
required_lines = extract_required_line_counts(content)
|
53
|
+
|
54
|
+
while lines.length < required_lines
|
55
|
+
lines << empty_middle_line(middle_indent)
|
56
|
+
end
|
57
|
+
|
58
|
+
lines
|
59
|
+
end
|
60
|
+
|
61
|
+
# 必要な行数を抽出
|
62
|
+
#
|
63
|
+
# @param [Hash] content コンテンツ
|
64
|
+
# @return [Integer] 必要な行数
|
65
|
+
def extract_required_line_counts(content)
|
66
|
+
# start_lineが1、end_lineが5の場合、必要な行数はブラケットを抜いて3行
|
67
|
+
# そのため、(end(5) - start(1)) + 1行 - ブラケット2行 = 3行となる
|
68
|
+
line_offset, without_brackets = 1, 2
|
69
|
+
|
70
|
+
(content[:end_line] - content[:start_line]) + line_offset - without_brackets
|
71
|
+
end
|
72
|
+
|
73
|
+
# 中間行のインデントを追加
|
74
|
+
#
|
75
|
+
# @param [Hash] content コンテンツ
|
76
|
+
# @param [String] middle_indent 中間行のインデント
|
77
|
+
# @return [Array<String>] 中間行のインデントを追加した行
|
78
|
+
def add_indent_for_middle_lines(content, middle_indent)
|
79
|
+
content[:text].split("\n").map do |line|
|
80
|
+
"#{middle_indent}\"#{line}\""
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# 中間行の空行を作成
|
85
|
+
#
|
86
|
+
# @param [String] middle_indent 中間行のインデント
|
87
|
+
# @return [String] 空行
|
88
|
+
def empty_middle_line(middle_indent)
|
89
|
+
"#{middle_indent}\"\""
|
90
|
+
end
|
91
|
+
|
92
|
+
# 不要な引用符を削除
|
93
|
+
#
|
94
|
+
# @param [String] line 行
|
95
|
+
# @return [String] 不要な引用符を削除した行
|
96
|
+
def delete_quotes(line)
|
97
|
+
line = delete_dup_quotes(line)
|
98
|
+
line = delete_jp_quotes(line)
|
99
|
+
delete_curved_quotes(line)
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
# 不要なダブルクオートを削除
|
105
|
+
#
|
106
|
+
# @param [String] line 行
|
107
|
+
# @return [String] 不要なダブルクオートを削除した行
|
108
|
+
def delete_dup_quotes(line)
|
109
|
+
# ""Hello""、""""
|
110
|
+
deletable_regs = [/"{2,}.+".*"/, /"{3,}/]
|
111
|
+
return line unless deletable_regs.any? { |reg| line.match?(reg) }
|
112
|
+
|
113
|
+
# ""
|
114
|
+
dup_reg = /"{2,}/
|
115
|
+
# """"に一致する場合は空白行なので、""に変換する
|
116
|
+
if line.strip.match?(deletable_regs[1])
|
117
|
+
line.gsub(dup_reg, '""')
|
118
|
+
else
|
119
|
+
# 行間にある余計なダブルクオートを削除するため、一度全てのダブルクオートを削除している
|
120
|
+
line = line.gsub('"', "")
|
121
|
+
# インデントの調整
|
122
|
+
indent_count = normalize_indent(line[/^\s*/].length)
|
123
|
+
line_start = /^(\s*)/
|
124
|
+
# 行頭にインデントとダブルクオートを追加
|
125
|
+
line = line.sub(line_start, "#{" " * indent_count}\"")
|
126
|
+
# 行末のダブルクオートを追加
|
127
|
+
"#{line}\""
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# 不要な鍵括弧を削除
|
132
|
+
#
|
133
|
+
# @param [String] line 行
|
134
|
+
# @return [String] 不要な鍵括弧を削除した行
|
135
|
+
def delete_jp_quotes(line)
|
136
|
+
# 「Hello」
|
137
|
+
deletable_reg = /「.*」/
|
138
|
+
return line unless line.match?(deletable_reg)
|
139
|
+
|
140
|
+
jp_quotes = [/「/, /」/]
|
141
|
+
jp_quotes.each { |quo| line = line.gsub(quo, "") }
|
142
|
+
line
|
143
|
+
end
|
144
|
+
|
145
|
+
# 不要な曲がった引用符を削除
|
146
|
+
#
|
147
|
+
# @param [String] line 行
|
148
|
+
# @return [String] 不要な曲がった引用符を削除した行
|
149
|
+
def delete_curved_quotes(line)
|
150
|
+
# “Hello”
|
151
|
+
deletable_reg = /“.*”/
|
152
|
+
return line unless line.match?(deletable_reg)
|
153
|
+
|
154
|
+
curved_quotes = [/“/, /”/]
|
155
|
+
curved_quotes.each { |quo| line = line.gsub(quo, "") }
|
156
|
+
line
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require "rainbow"
|
2
|
+
|
3
|
+
module JpQuest
|
4
|
+
# JpQuest gemについてのヘルプを表示するクラス
|
5
|
+
class Help
|
6
|
+
# JpQuest gemについてのヘルプを表示する
|
7
|
+
#
|
8
|
+
# @return [void]
|
9
|
+
def self.help
|
10
|
+
puts <<~HELP
|
11
|
+
#{cyan("=== JpQuest Help ===================================================================").bold}\n
|
12
|
+
#{help_warning}
|
13
|
+
#{help_intro}
|
14
|
+
#{help_steps}
|
15
|
+
#{help_init_options}
|
16
|
+
#{help_information}
|
17
|
+
#{cyan("====================================================================================").bold}
|
18
|
+
HELP
|
19
|
+
end
|
20
|
+
|
21
|
+
# 警告
|
22
|
+
#
|
23
|
+
# @return [String]
|
24
|
+
def self.help_warning
|
25
|
+
<<~WARNING
|
26
|
+
#{red("Warning:").bold} Please be careful your OpenAI API usage cost.
|
27
|
+
WARNING
|
28
|
+
end
|
29
|
+
|
30
|
+
# gemの説明
|
31
|
+
#
|
32
|
+
# @return [String]
|
33
|
+
def self.help_intro
|
34
|
+
<<~INTRO
|
35
|
+
#{cyan("Introduction:").bold}
|
36
|
+
Translator for #{green(".snbt")} files.
|
37
|
+
If you want to translate to other languages than Japanese,
|
38
|
+
please add the #{green("exchange_language")} option during initialization.
|
39
|
+
Example: #{green("JpQuest::Performer.new(exchange_language: \"English\")")}
|
40
|
+
INTRO
|
41
|
+
end
|
42
|
+
|
43
|
+
# 使用手順
|
44
|
+
#
|
45
|
+
# @return [String]
|
46
|
+
def self.help_steps
|
47
|
+
<<~STEPS
|
48
|
+
#{cyan("Steps:").bold}
|
49
|
+
1. exec #{green("touch .env")} bash command
|
50
|
+
2. Add #{green("OPENAI_API_KEY=your_api_key")} to .env
|
51
|
+
3. Optional: Add #{green("OPENAI_MODEL=some_openai_model")} to .env (default: gpt-4o-mini)
|
52
|
+
4. Add "quests" directory to your project
|
53
|
+
5. #{green("gem install jp_quest")} or #{green("gem \"jp_quest\"")}
|
54
|
+
6. Add #{green("require \"jp_quest\"")}
|
55
|
+
7. Add #{green("jp_quest = JpQuest::Performer.new")}
|
56
|
+
8. #{green("jp_quest.perform(\"file_path\")")} or
|
57
|
+
#{green("jp_quest.perform_directory(dir_path: \"dir_path\")")}
|
58
|
+
9. Check "output" directory
|
59
|
+
STEPS
|
60
|
+
end
|
61
|
+
|
62
|
+
# newメソッドのオプション
|
63
|
+
#
|
64
|
+
# @return [String]
|
65
|
+
def self.help_init_options
|
66
|
+
<<~OPTIONS
|
67
|
+
#{cyan("Initialize Options:").bold}
|
68
|
+
output_logs:
|
69
|
+
Want to output OpenAI usage logs?
|
70
|
+
(default: true)
|
71
|
+
except_words:
|
72
|
+
Words that you don't want to translate
|
73
|
+
(default: empty array)
|
74
|
+
exchange_language:
|
75
|
+
Which language do you want to translate to?
|
76
|
+
(default: japanese)
|
77
|
+
display_help:
|
78
|
+
Want to display help?
|
79
|
+
(default: true)
|
80
|
+
OPTIONS
|
81
|
+
end
|
82
|
+
|
83
|
+
# その他gemに関する情報
|
84
|
+
#
|
85
|
+
# @return [String]
|
86
|
+
def self.help_information
|
87
|
+
<<~INFORMATION
|
88
|
+
#{cyan("Information:").bold}
|
89
|
+
jp_quest:
|
90
|
+
#{link("https://github.com/milkeclair/jp_quest")}
|
91
|
+
current version: #{JpQuest::VERSION}
|
92
|
+
translator:
|
93
|
+
#{link("https://github.com/milkeclair/jp_translator_from_gpt")}
|
94
|
+
current version: #{JpTranslatorFromGpt::VERSION}
|
95
|
+
INFORMATION
|
96
|
+
end
|
97
|
+
|
98
|
+
# 出力を青色にする
|
99
|
+
#
|
100
|
+
# @param [String] str
|
101
|
+
# @return [String]
|
102
|
+
def self.cyan(str)
|
103
|
+
Rainbow(str).cyan
|
104
|
+
end
|
105
|
+
|
106
|
+
# 出力を緑色にする
|
107
|
+
#
|
108
|
+
# @param [String] str
|
109
|
+
# @return [String]
|
110
|
+
def self.green(str)
|
111
|
+
Rainbow(str).green
|
112
|
+
end
|
113
|
+
|
114
|
+
# 出力を赤色にする
|
115
|
+
#
|
116
|
+
# @param [String] str
|
117
|
+
# @return [String]
|
118
|
+
def self.red(str)
|
119
|
+
Rainbow(str).red
|
120
|
+
end
|
121
|
+
|
122
|
+
# 出力をリンクのスタイルにする
|
123
|
+
#
|
124
|
+
# @param [String] str
|
125
|
+
# @return [String]
|
126
|
+
def self.link(str)
|
127
|
+
Rainbow(str).underline.bright
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module JpQuest
|
2
|
+
# インデントを扱うモジュール
|
3
|
+
module IndentHelper
|
4
|
+
# インデントを作成
|
5
|
+
#
|
6
|
+
# @param [Integer] indent インデント数
|
7
|
+
# @return [String] インデント
|
8
|
+
def create_indent(indent)
|
9
|
+
" " * indent
|
10
|
+
end
|
11
|
+
|
12
|
+
# 中間行のインデントを作成
|
13
|
+
#
|
14
|
+
# @param [Integer] indent インデント数
|
15
|
+
# @return [String] 中間行のインデント
|
16
|
+
def middle_indent(indent)
|
17
|
+
" " * (indent + 1)
|
18
|
+
end
|
19
|
+
|
20
|
+
# インデントを調整
|
21
|
+
#
|
22
|
+
# @param [Integer] indent インデント数
|
23
|
+
# @return [Integer] 調整後のインデント数
|
24
|
+
def normalize_indent(indent)
|
25
|
+
dup_indent = 12
|
26
|
+
if indent > dup_indent
|
27
|
+
half = 2
|
28
|
+
half_indent = indent / half
|
29
|
+
# インデントの数は偶数にする
|
30
|
+
half_indent.even? ? half_indent : half_indent + 1
|
31
|
+
else
|
32
|
+
indent
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require "jp_translator_from_gpt"
|
2
|
+
require_relative "help"
|
3
|
+
require_relative "error"
|
4
|
+
require_relative "reader"
|
5
|
+
require_relative "writer"
|
6
|
+
|
7
|
+
module JpQuest
|
8
|
+
# 翻訳を実行するクラス
|
9
|
+
# JpTranslatorFromGptを使用して翻訳を行う
|
10
|
+
class Performer
|
11
|
+
# @param [Boolean] output_logs ログを出力するか
|
12
|
+
# @param [Array<String>] except_words 翻訳しない単語
|
13
|
+
# @param [String] exchange_language どの言語に翻訳するか
|
14
|
+
# @param [Boolean] display_help ヘルプを表示するか
|
15
|
+
# @return [JpQuest::Performer]
|
16
|
+
def initialize(output_logs: true, except_words: [], exchange_language: "japanese", display_help: true)
|
17
|
+
@translator = JpTranslatorFromGpt::Translator.new(
|
18
|
+
output_logs: output_logs,
|
19
|
+
except_words: except_words,
|
20
|
+
exchange_language: exchange_language
|
21
|
+
)
|
22
|
+
@reader = nil
|
23
|
+
@writer = nil
|
24
|
+
@progress_bar = nil
|
25
|
+
|
26
|
+
JpQuest.help if display_help
|
27
|
+
end
|
28
|
+
|
29
|
+
# ファイルを翻訳して出力する
|
30
|
+
#
|
31
|
+
# @param [String] file_path ファイルのパス
|
32
|
+
# @return [void]
|
33
|
+
def perform(file_path)
|
34
|
+
file_path = File.expand_path(file_path)
|
35
|
+
validate_path(file_path)
|
36
|
+
|
37
|
+
@reader, @writer = JpQuest::Reader.new(file_path), JpQuest::Writer.new(file_path)
|
38
|
+
results = @reader.extract_all.flatten
|
39
|
+
@progress_bar = JpQuest.create_progress_bar(file_path, results.length)
|
40
|
+
|
41
|
+
results.each do |result|
|
42
|
+
result[:text] = @translator.translate(result[:text])
|
43
|
+
@writer.overwrites(result)
|
44
|
+
@progress_bar.increment
|
45
|
+
end
|
46
|
+
|
47
|
+
puts "Completed!"
|
48
|
+
end
|
49
|
+
|
50
|
+
# ディレクトリ内のファイルを翻訳して出力する
|
51
|
+
#
|
52
|
+
# @param [String] dir_path ディレクトリのパス
|
53
|
+
# @return [void]
|
54
|
+
def perform_directory(dir_path: "quests")
|
55
|
+
dir_path = File.expand_path(dir_path)
|
56
|
+
validate_path(dir_path)
|
57
|
+
|
58
|
+
# **でサブディレクトリも含めて取得
|
59
|
+
Dir.glob("#{dir_path}/**.snbt").each do |file_path|
|
60
|
+
perform(file_path)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# ファイルの存在を確認する
|
65
|
+
# 存在しない場合はPathNotFoundErrorを投げる
|
66
|
+
#
|
67
|
+
# @param [String] path ファイルのパス
|
68
|
+
# @return [void]
|
69
|
+
def validate_path(path)
|
70
|
+
path = File.expand_path(path)
|
71
|
+
raise JpQuest::PathNotFoundError.new(path) unless File.exist?(path)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "extractor/title"
|
4
|
+
require_relative "extractor/subtitle"
|
5
|
+
require_relative "extractor/description"
|
6
|
+
|
7
|
+
module JpQuest
|
8
|
+
# SNBT形式のファイルからタイトル、サブタイトル、説明を抽出するクラス
|
9
|
+
class Reader
|
10
|
+
include TitleExtractor
|
11
|
+
include SubtitleExtractor
|
12
|
+
include DescriptionExtractor
|
13
|
+
|
14
|
+
DESC_START_LENGTH = 14
|
15
|
+
DESC_END_LENGTH = -2
|
16
|
+
|
17
|
+
# @param [String] file_path ファイルのパス
|
18
|
+
# @return [JpQuest::Reader]
|
19
|
+
def initialize(file_path)
|
20
|
+
@file_path = file_path
|
21
|
+
end
|
22
|
+
|
23
|
+
# タイトル、サブタイトル、説明を抽出する
|
24
|
+
#
|
25
|
+
# @return [Array<Array<Hash>>] タイトル、サブタイトル、説明の配列
|
26
|
+
def extract_all
|
27
|
+
titles = extract_titles
|
28
|
+
subtitles = extract_subtitles
|
29
|
+
descriptions = extract_descriptions
|
30
|
+
|
31
|
+
[titles, subtitles, descriptions]
|
32
|
+
end
|
33
|
+
|
34
|
+
# タイトルを抽出する
|
35
|
+
#
|
36
|
+
# @return [Array<Hash>] タイトル、行番号、インデントの配列
|
37
|
+
def extract_titles
|
38
|
+
super(@file_path)
|
39
|
+
end
|
40
|
+
|
41
|
+
# サブタイトルを抽出する
|
42
|
+
#
|
43
|
+
# @return [Array<Hash>] サブタイトル、行番号、インデントの配列
|
44
|
+
def extract_subtitles
|
45
|
+
super(@file_path)
|
46
|
+
end
|
47
|
+
|
48
|
+
# 説明を抽出する
|
49
|
+
#
|
50
|
+
# @return [Array<Hash>] 説明、開始行、終了行、インデントの配列
|
51
|
+
def extract_descriptions
|
52
|
+
super(@file_path)
|
53
|
+
end
|
54
|
+
|
55
|
+
# インデントを数える
|
56
|
+
#
|
57
|
+
# @param [String] unstripped_line stripされていない行
|
58
|
+
# @return [Integer] インデントの数
|
59
|
+
def count_indent(unstripped_line)
|
60
|
+
unstripped_line.length - unstripped_line.lstrip.length
|
61
|
+
end
|
62
|
+
|
63
|
+
# title: "some title"のような形式から、"some title"を抽出する
|
64
|
+
# 説明の場合は、description: ["some description"]のような形式から、"some description"を抽出する
|
65
|
+
#
|
66
|
+
# @param [String] line 行
|
67
|
+
# @param [Boolean] is_desc 説明かどうか
|
68
|
+
# @return [String] タイトル or サブタイトル or 説明
|
69
|
+
def extract_oneline(line, is_desc: false)
|
70
|
+
stripped_line = line.strip
|
71
|
+
return stripped_line.split(":", 2)[1] unless is_desc
|
72
|
+
|
73
|
+
if oneline_description?(line)
|
74
|
+
stripped_line[DESC_START_LENGTH..DESC_END_LENGTH]
|
75
|
+
elsif start_of?(line, key: :description)
|
76
|
+
stripped_line.split("[", 2)[1]
|
77
|
+
else
|
78
|
+
stripped_line.split("]", 2)[0]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# 1行の説明かどうか
|
83
|
+
#
|
84
|
+
# @param [String] line 行
|
85
|
+
# @return [Boolean]
|
86
|
+
def oneline_description?(line)
|
87
|
+
stripped_line = line.strip
|
88
|
+
start_of?(line, key: :description) && stripped_line.end_with?("]")
|
89
|
+
end
|
90
|
+
|
91
|
+
# どのコンテンツの開始行か
|
92
|
+
#
|
93
|
+
# @param [String] line 行
|
94
|
+
# @param [Symbol] key コンテンツの種類
|
95
|
+
# @return [Boolean]
|
96
|
+
def start_of?(line, key:)
|
97
|
+
stripped_line = line.strip
|
98
|
+
sections = {
|
99
|
+
title: "title:",
|
100
|
+
subtitle: "subtitle:",
|
101
|
+
description: "description: ["
|
102
|
+
}
|
103
|
+
|
104
|
+
stripped_line.start_with?(sections[key])
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require_relative "error"
|
2
|
+
require_relative "formatter"
|
3
|
+
require_relative "indent_helper"
|
4
|
+
|
5
|
+
module JpQuest
|
6
|
+
# 翻訳された内容を整形して出力するクラス
|
7
|
+
class Writer
|
8
|
+
include IndentHelper
|
9
|
+
|
10
|
+
# @param [String] file_path ファイルのパス
|
11
|
+
# @return [JpQuest::Writer]
|
12
|
+
def initialize(file_path)
|
13
|
+
@input_file_path = file_path
|
14
|
+
@output_file_path = file_path.gsub("quests", "output/quests")
|
15
|
+
@formatter = JpQuest::Formatter.new
|
16
|
+
end
|
17
|
+
|
18
|
+
# 翻訳された内容でoutput_file_pathを上書きする
|
19
|
+
#
|
20
|
+
# @param [Hash] translated_contents 翻訳された内容
|
21
|
+
# @return [void]
|
22
|
+
def overwrites(translated_contents)
|
23
|
+
# ディレクトリが存在しない場合は作成
|
24
|
+
FileUtils.mkdir_p(File.dirname(@output_file_path))
|
25
|
+
|
26
|
+
# 一度上書きしている場合は上書き後のファイルを読み込む
|
27
|
+
# 常に上書き前のファイルを読み込むと、前回の上書きが消えてしまう
|
28
|
+
lines = File.readlines(first_overwrite? ? @input_file_path : @output_file_path)
|
29
|
+
formatted_lines = overwrite_lines(lines, translated_contents)
|
30
|
+
|
31
|
+
File.open(@output_file_path, "w") do |file|
|
32
|
+
file.puts formatted_lines
|
33
|
+
end
|
34
|
+
|
35
|
+
handle_line_count_error(@output_file_path, lines.length)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# 行を上書きする
|
41
|
+
#
|
42
|
+
# @param [Array<String>] lines 行
|
43
|
+
# @param [Hash] content コンテンツ
|
44
|
+
# @return [Array<String>] 上書きされた行
|
45
|
+
def overwrite_lines(lines, content)
|
46
|
+
indent = create_indent(content[:indent])
|
47
|
+
overwritable_lines = @formatter.format_overwritable_lines(content, indent)
|
48
|
+
lines[content[:start_line]..content[:end_line]] = overwritable_lines.split("\n")
|
49
|
+
lines
|
50
|
+
end
|
51
|
+
|
52
|
+
# 最初の上書きかどうか
|
53
|
+
#
|
54
|
+
# @return [Boolean] 最初の上書きかどうか
|
55
|
+
def first_overwrite?
|
56
|
+
!File.exist?(@output_file_path)
|
57
|
+
end
|
58
|
+
|
59
|
+
# 翻訳前と翻訳後の行数が異なる場合はエラーを発生させる
|
60
|
+
#
|
61
|
+
# @param [String] output_file_path 出力ファイルのパス
|
62
|
+
# @param [Integer] before_line_count 翻訳前の行数
|
63
|
+
# @return [void]
|
64
|
+
def handle_line_count_error(output_file_path, before_line_count)
|
65
|
+
after_line_count = File.readlines(output_file_path).length
|
66
|
+
return if before_line_count == after_line_count
|
67
|
+
|
68
|
+
raise JpQuest::InvalidLineCountError.new(before_line_count, after_line_count)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/jp_quest.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ruby-progressbar"
|
4
|
+
require_relative "jp_quest/version"
|
5
|
+
require_relative "jp_quest/help"
|
6
|
+
require_relative "jp_quest/performer"
|
7
|
+
|
8
|
+
# SNBT形式のファイルを翻訳する
|
9
|
+
# 翻訳できるプロパティ
|
10
|
+
# - title
|
11
|
+
# - subtitle
|
12
|
+
# - description
|
13
|
+
module JpQuest
|
14
|
+
# JpQuest gemについてのヘルプを表示する
|
15
|
+
#
|
16
|
+
# @return [void]
|
17
|
+
def self.help
|
18
|
+
JpQuest::Help.help
|
19
|
+
end
|
20
|
+
|
21
|
+
# プログレスバーを生成する
|
22
|
+
#
|
23
|
+
# @param [String] file_path ファイルのパス
|
24
|
+
# @param [Integer] total プログレスバーの合計数
|
25
|
+
# @return [ProgressBar::Base] プログレスバー
|
26
|
+
def self.create_progress_bar(file_path, total)
|
27
|
+
# パスの内、カレントディレクトリ配下のパス以外は邪魔なので削除
|
28
|
+
# 例: /Users/user/quests/some.snbt -> /quests/some.snbt
|
29
|
+
puts "\nFile path: #{file_path.gsub(Dir.pwd, "")}"
|
30
|
+
|
31
|
+
ProgressBar.create(
|
32
|
+
title: "Translating...",
|
33
|
+
total: total,
|
34
|
+
progress_mark: "#",
|
35
|
+
format: "%t [%B]",
|
36
|
+
length: 80,
|
37
|
+
projector: {
|
38
|
+
type: "smoothed",
|
39
|
+
strength: 0.1
|
40
|
+
}
|
41
|
+
)
|
42
|
+
end
|
43
|
+
end
|
data/rake_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class RakeHelper
|
4
|
+
GITHUB_PACKAGES_PUSH_COMMAND =
|
5
|
+
"gem push --key github --host https://rubygems.pkg.github.com/milkeclair " \
|
6
|
+
"pkg/jp_quest-#{JpQuest::VERSION}.gem".freeze
|
7
|
+
|
8
|
+
RUBYGEMS_PUSH_COMMAND =
|
9
|
+
"gem push --host https://rubygems.org " \
|
10
|
+
"pkg/jp_quest-#{JpQuest::VERSION}.gem".freeze
|
11
|
+
|
12
|
+
def self.init_rake_tasks
|
13
|
+
RSpec::Core::RakeTask.new(:spec) { |task| task.verbose = false }
|
14
|
+
RuboCop::RakeTask.new
|
15
|
+
YARD::Rake::YardocTask.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.build_gem
|
19
|
+
abort("gemのビルドに失敗しました") unless system("rake build")
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.push_to_github_packages
|
23
|
+
abort("githubへのgemのpushに失敗しました") unless system(GITHUB_PACKAGES_PUSH_COMMAND)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.push_to_rubygems
|
27
|
+
abort("rubygemsへのgemのpushに失敗しました") unless system(RUBYGEMS_PUSH_COMMAND)
|
28
|
+
end
|
29
|
+
end
|
data/sig/jp_quest.rbs
ADDED
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jp_quest
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- milkeclair
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-10-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: jp_translator_from_gpt
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.1.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.1.0
|
27
|
+
description: ftbquestを日本語化する
|
28
|
+
email:
|
29
|
+
- milkeclair.noreply@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- ".licensed.yml"
|
35
|
+
- ".rspec"
|
36
|
+
- ".rubocop.yml"
|
37
|
+
- CHANGELOG.md
|
38
|
+
- LICENSE.txt
|
39
|
+
- README.md
|
40
|
+
- Rakefile
|
41
|
+
- dist/Gemfile
|
42
|
+
- dist/example.rb
|
43
|
+
- dist/start.bat
|
44
|
+
- lib/jp_quest.rb
|
45
|
+
- lib/jp_quest/error.rb
|
46
|
+
- lib/jp_quest/extractor/description.rb
|
47
|
+
- lib/jp_quest/extractor/subtitle.rb
|
48
|
+
- lib/jp_quest/extractor/title.rb
|
49
|
+
- lib/jp_quest/formatter.rb
|
50
|
+
- lib/jp_quest/help.rb
|
51
|
+
- lib/jp_quest/indent_helper.rb
|
52
|
+
- lib/jp_quest/performer.rb
|
53
|
+
- lib/jp_quest/reader.rb
|
54
|
+
- lib/jp_quest/version.rb
|
55
|
+
- lib/jp_quest/writer.rb
|
56
|
+
- rake_helper.rb
|
57
|
+
- sig/jp_quest.rbs
|
58
|
+
homepage: https://github.com/milkeclair/jp_quest
|
59
|
+
licenses:
|
60
|
+
- MIT
|
61
|
+
metadata:
|
62
|
+
homepage_uri: https://github.com/milkeclair/jp_quest
|
63
|
+
source_code_uri: https://github.com/milkeclair/jp_quest/blob/main
|
64
|
+
changelog_uri: https://github.com/milkeclair/jp_quest/blob/main/CHANGELOG.md
|
65
|
+
rubygems_mfa_required: 'true'
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options: []
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: 3.0.0
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
requirements: []
|
81
|
+
rubygems_version: 3.5.21
|
82
|
+
signing_key:
|
83
|
+
specification_version: 4
|
84
|
+
summary: translate to japanese for ftbquest
|
85
|
+
test_files: []
|