jp_quest 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|