jp_quest 0.2.0 → 0.3.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 +4 -4
- data/CHANGELOG.md +9 -1
- data/README.md +1 -1
- data/dist/Gemfile +1 -1
- data/dist/example.rb +1 -1
- data/lib/jp_quest/snbt/description_extractor.rb +118 -0
- data/lib/jp_quest/snbt/formatter.rb +168 -0
- data/lib/jp_quest/snbt/performer.rb +76 -0
- data/lib/jp_quest/snbt/reader.rb +102 -0
- data/lib/jp_quest/snbt/subtitle_extractor.rb +32 -0
- data/lib/jp_quest/snbt/title_extractor.rb +32 -0
- data/lib/jp_quest/snbt/writer.rb +74 -0
- data/lib/jp_quest/{help.rb → util/help.rb} +2 -2
- data/lib/jp_quest/{indent_helper.rb → util/indent_helper.rb} +8 -16
- data/lib/jp_quest/{version.rb → util/version.rb} +1 -1
- data/lib/jp_quest.rb +3 -3
- metadata +13 -13
- data/lib/jp_quest/extractor/description.rb +0 -112
- data/lib/jp_quest/extractor/subtitle.rb +0 -26
- data/lib/jp_quest/extractor/title.rb +0 -26
- data/lib/jp_quest/formatter.rb +0 -148
- data/lib/jp_quest/performer.rb +0 -74
- data/lib/jp_quest/reader.rb +0 -107
- data/lib/jp_quest/writer.rb +0 -72
- /data/lib/jp_quest/{error.rb → util/error.rb} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 90987ac46d58c0e6bf724a01a86b5909693c64c53ee46cbf0a8efc49909e2cfe
|
4
|
+
data.tar.gz: 9708d0bab80b268cf03bdd4c4a946f34f5d79a5c39d7e947b4f57d20a4098183
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 88da5d49a1abea3c2c32b74d06fbf8d14584a7f99440004ce4342c1ed77c1fdd9b2703154a48ed415257b31ecd105d98c46719609126460bffa0a92cfcafb672
|
7
|
+
data.tar.gz: 9a66c779465e0584d11513367a97b7917783e30d3044bd0b19604376f3fd7efc53ba6515593eea7b1f5008054507e49f3ef830db780eddd725018c53d2abf5d7
|
data/CHANGELOG.md
CHANGED
@@ -19,4 +19,12 @@
|
|
19
19
|
## [0.2.0] - 2024-10/9
|
20
20
|
|
21
21
|
- 出力時のダブルクオート数、インデント数が崩れていたのを出来るだけ抑制
|
22
|
-
- quests.snbtのパス名も変換されていたのを修正
|
22
|
+
- quests.snbtのパス名も変換されていたのを修正
|
23
|
+
|
24
|
+
## [0.2.1] - 2024-10/10
|
25
|
+
|
26
|
+
- \と;を削除する記号に追加
|
27
|
+
|
28
|
+
## [0.3.0] - 2024-10/12
|
29
|
+
|
30
|
+
- MODの翻訳機能を追加しやすいように、モジュールの構造を変更
|
data/README.md
CHANGED
data/dist/Gemfile
CHANGED
data/dist/example.rb
CHANGED
@@ -0,0 +1,118 @@
|
|
1
|
+
require_relative "../util/indent_helper"
|
2
|
+
|
3
|
+
module JpQuest
|
4
|
+
module SNBT
|
5
|
+
# SNBT形式のファイルからdescription: ["some description"]を抽出するモジュール
|
6
|
+
module DescriptionExtractor
|
7
|
+
include IndentHelper
|
8
|
+
|
9
|
+
# description: ["some description"]を抽出する
|
10
|
+
#
|
11
|
+
# @param [String] file_path ファイルのパス
|
12
|
+
# @return [Array<Hash>] 説明、開始行番号、終了行番号の配列
|
13
|
+
def extract_descriptions(file_path)
|
14
|
+
lines = File.readlines(file_path)
|
15
|
+
extract_from_file(lines)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# ファイルから説明を抽出する
|
21
|
+
#
|
22
|
+
# @param [Array<String>] lines 行の配列
|
23
|
+
# @return [Array<Hash>] 説明、開始行番号、終了行番号、インデントのハッシュの配列
|
24
|
+
def extract_from_file(lines)
|
25
|
+
descs = []
|
26
|
+
desc_content = []
|
27
|
+
start_line = nil
|
28
|
+
|
29
|
+
lines.each_with_index do |line, index|
|
30
|
+
indent = count_indent(line)
|
31
|
+
|
32
|
+
# 1行の説明の場合はそのままハッシュに変換
|
33
|
+
# 複数行の場合は、開始行と終了行の間の説明を抽出する
|
34
|
+
if oneline?(line)
|
35
|
+
descs << build_oneline(line, index, indent)
|
36
|
+
elsif start_line?(line)
|
37
|
+
start_line = index
|
38
|
+
elsif middle_line?(line, start_line)
|
39
|
+
desc_content << line.strip
|
40
|
+
elsif end_line?(line, start_line)
|
41
|
+
descs << build_multiline(desc_content, start_line, index, indent)
|
42
|
+
start_line = nil
|
43
|
+
desc_content = []
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
descs
|
48
|
+
end
|
49
|
+
|
50
|
+
# 1行かどうか
|
51
|
+
#
|
52
|
+
# @param [String] line 行
|
53
|
+
# @return [Boolean]
|
54
|
+
def oneline?(line)
|
55
|
+
oneline_description?(line)
|
56
|
+
end
|
57
|
+
|
58
|
+
# 開始行かどうか
|
59
|
+
#
|
60
|
+
# @param [String] line 行
|
61
|
+
# @return [Boolean]
|
62
|
+
def start_line?(line)
|
63
|
+
start_of?(line, key: :description)
|
64
|
+
end
|
65
|
+
|
66
|
+
# 終了行かどうか
|
67
|
+
#
|
68
|
+
# @param [String] line 行
|
69
|
+
# @param [Integer] start_line 開始行番号
|
70
|
+
# @return [Boolean]
|
71
|
+
def end_line?(line, start_line)
|
72
|
+
line.strip.end_with?("]") && start_line
|
73
|
+
end
|
74
|
+
|
75
|
+
# 中間行かどうか
|
76
|
+
#
|
77
|
+
# @param [String] line 行
|
78
|
+
# @param [Integer] start_line 開始行番号
|
79
|
+
# @return [Boolean]
|
80
|
+
def middle_line?(line, start_line)
|
81
|
+
line.strip != "]" && start_line
|
82
|
+
end
|
83
|
+
|
84
|
+
# 1行の処理
|
85
|
+
#
|
86
|
+
# @param [String] line 行
|
87
|
+
# @param [Integer] index 行番号
|
88
|
+
# @param [Integer] indent インデント
|
89
|
+
# @return [Hash] 説明、開始行番号、終了行番号、インデントのハッシュ
|
90
|
+
def build_oneline(line, index, indent)
|
91
|
+
{
|
92
|
+
type: :description,
|
93
|
+
text: extract_oneline(line, is_desc: true),
|
94
|
+
start_line: index,
|
95
|
+
end_line: index,
|
96
|
+
indent: indent
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
# 複数行の処理
|
101
|
+
#
|
102
|
+
# @param [Array<String>] content 説明の配列
|
103
|
+
# @param [Integer] start_line 開始行番号
|
104
|
+
# @param [Integer] index 行番号
|
105
|
+
# @param [Integer] indent インデント
|
106
|
+
# @return [Hash] 説明、開始行番号、終了行番号、インデントのハッシュ
|
107
|
+
def build_multiline(content, start_line, index, indent)
|
108
|
+
{
|
109
|
+
type: :description,
|
110
|
+
text: content.join("\n"),
|
111
|
+
start_line: start_line,
|
112
|
+
end_line: index,
|
113
|
+
indent: indent
|
114
|
+
}
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require_relative "../util/indent_helper"
|
2
|
+
|
3
|
+
module JpQuest
|
4
|
+
module SNBT
|
5
|
+
# 翻訳された内容をSNBT形式に整形するクラス
|
6
|
+
class Formatter
|
7
|
+
include IndentHelper
|
8
|
+
|
9
|
+
# 保存できるように整形
|
10
|
+
#
|
11
|
+
# @param [Hash] content コンテンツ
|
12
|
+
# @param [String] indent インデント
|
13
|
+
# @return [String] SNBT形式に整形したコンテンツ
|
14
|
+
def format_overwritable_lines(content, indent)
|
15
|
+
full_lines = add_missing_lines(content)
|
16
|
+
format_for_snbt(full_lines, indent, content)
|
17
|
+
end
|
18
|
+
|
19
|
+
# SNBT形式に整形
|
20
|
+
#
|
21
|
+
# @param [Array<String>] lines 行
|
22
|
+
# @param [String] indent インデント
|
23
|
+
# @param [Hash] content コンテンツ
|
24
|
+
# @return [String] SNBT形式に整形した行
|
25
|
+
def format_for_snbt(lines, indent, content)
|
26
|
+
lines = prepare_lines_for_snbt(lines, content)
|
27
|
+
formatted_lines = format_lines(lines, indent, content)
|
28
|
+
"#{indent}#{content[:type]}: #{formatted_lines}"
|
29
|
+
end
|
30
|
+
|
31
|
+
# 不足している行を追加
|
32
|
+
#
|
33
|
+
# @param [Hash] content コンテンツ
|
34
|
+
# @return [void]
|
35
|
+
def add_missing_lines(content)
|
36
|
+
required_lines = extract_required_line_counts(content)
|
37
|
+
lines = content[:text].split("\n")
|
38
|
+
|
39
|
+
while lines.length < required_lines
|
40
|
+
lines << empty_middle_line(content[:indent])
|
41
|
+
end
|
42
|
+
|
43
|
+
lines
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# 不要な文字を削除する
|
49
|
+
#
|
50
|
+
# @param [String] lines 行
|
51
|
+
# @param [Hash] content コンテンツ
|
52
|
+
# @return [Array<String>] 不要な文字を削除した行
|
53
|
+
def prepare_lines_for_snbt(lines, content)
|
54
|
+
lines.map! { |line| delete_unwanted_symbols(line) }
|
55
|
+
lines.map!(&:strip) unless content[:type] == :description
|
56
|
+
lines
|
57
|
+
end
|
58
|
+
|
59
|
+
# SNBT形式に変換しやすい形に整形
|
60
|
+
#
|
61
|
+
# @param [Array<String>] lines 行
|
62
|
+
# @param [String] indent インデント
|
63
|
+
# @param [Hash] content コンテンツ
|
64
|
+
# @return [String] SNBT形式に変換しやすく整形した行
|
65
|
+
def format_lines(lines, indent, content)
|
66
|
+
if lines.length == 1
|
67
|
+
content[:type] == :description ? "[#{lines[0].strip}]" : lines[0].strip.to_s
|
68
|
+
else
|
69
|
+
# [
|
70
|
+
# "Hello"
|
71
|
+
# "World"
|
72
|
+
# ]
|
73
|
+
mid_indent = middle_indent(content[:indent])
|
74
|
+
lines = lines.map { |line| "#{mid_indent}#{line.strip}" }
|
75
|
+
"[\n#{lines.join("\n")}\n#{indent}]"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# 必要な行数を抽出
|
80
|
+
#
|
81
|
+
# @param [Hash] content コンテンツ
|
82
|
+
# @return [Integer] 必要な行数
|
83
|
+
def extract_required_line_counts(content)
|
84
|
+
# start_lineが1、end_lineが5の場合、必要な行数はブラケットを抜いて3行
|
85
|
+
# そのため、(end(5) - start(1)) + 1行 - ブラケット2行 = 3行となる
|
86
|
+
line_offset, without_brackets = 1, 2
|
87
|
+
|
88
|
+
(content[:end_line] - content[:start_line]) + line_offset - without_brackets
|
89
|
+
end
|
90
|
+
|
91
|
+
# 中間行の空行を作成
|
92
|
+
#
|
93
|
+
# @return [String] 空行
|
94
|
+
def empty_middle_line(indent)
|
95
|
+
middle_indent(indent).to_s
|
96
|
+
end
|
97
|
+
|
98
|
+
# 不要な記号を削除
|
99
|
+
#
|
100
|
+
# @param [String] line 行
|
101
|
+
# @return [String] 不要な記号を削除した行
|
102
|
+
def delete_unwanted_symbols(line)
|
103
|
+
line = delete_backslash(line)
|
104
|
+
line = delete_semicolon(line)
|
105
|
+
line = delete_dup_quotes(line)
|
106
|
+
line = delete_jp_quotes(line)
|
107
|
+
delete_curved_quotes(line)
|
108
|
+
end
|
109
|
+
|
110
|
+
# 不要なバックスラッシュを削除
|
111
|
+
#
|
112
|
+
# @param [String] line 行
|
113
|
+
# @return [String] 不要なバックスラッシュを削除した行
|
114
|
+
def delete_backslash(line)
|
115
|
+
line.gsub("\\", "")
|
116
|
+
end
|
117
|
+
|
118
|
+
# 不要なセミコロンを削除
|
119
|
+
#
|
120
|
+
# @param [String] line 行
|
121
|
+
# @return [String] 不要なセミコロンを削除した行
|
122
|
+
def delete_semicolon(line)
|
123
|
+
line.gsub(";", "")
|
124
|
+
end
|
125
|
+
|
126
|
+
# 不要なダブルクオートを削除
|
127
|
+
#
|
128
|
+
# @param [String] line 行
|
129
|
+
# @return [String] 不要なダブルクオートを削除した行
|
130
|
+
def delete_dup_quotes(line)
|
131
|
+
# 行間にある余計なダブルクオートを削除するため、一度全てのダブルクオートを削除している
|
132
|
+
# 全て削除したあと、行頭、行末にダブルクオートを追加する
|
133
|
+
line = line.gsub('"', "")
|
134
|
+
line_start = /^(\s*)/
|
135
|
+
line = line.sub(line_start, "\"")
|
136
|
+
"#{line}\""
|
137
|
+
end
|
138
|
+
|
139
|
+
# 不要な鍵括弧を削除
|
140
|
+
#
|
141
|
+
# @param [String] line 行
|
142
|
+
# @return [String] 不要な鍵括弧を削除した行
|
143
|
+
def delete_jp_quotes(line)
|
144
|
+
# 「Hello」
|
145
|
+
deletable_reg = /「.*」/
|
146
|
+
return line unless line.match?(deletable_reg)
|
147
|
+
|
148
|
+
jp_quotes = [/「/, /」/]
|
149
|
+
jp_quotes.each { |quo| line = line.gsub(quo, "") }
|
150
|
+
line
|
151
|
+
end
|
152
|
+
|
153
|
+
# 不要な曲がった引用符を削除
|
154
|
+
#
|
155
|
+
# @param [String] line 行
|
156
|
+
# @return [String] 不要な曲がった引用符を削除した行
|
157
|
+
def delete_curved_quotes(line)
|
158
|
+
# “Hello”
|
159
|
+
deletable_reg = /“.*”/
|
160
|
+
return line unless line.match?(deletable_reg)
|
161
|
+
|
162
|
+
curved_quotes = [/“/, /”/]
|
163
|
+
curved_quotes.each { |quo| line = line.gsub(quo, "") }
|
164
|
+
line
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require "jp_translator_from_gpt"
|
2
|
+
require_relative "../util/help"
|
3
|
+
require_relative "../util/error"
|
4
|
+
require_relative "reader"
|
5
|
+
require_relative "writer"
|
6
|
+
|
7
|
+
module JpQuest
|
8
|
+
module SNBT
|
9
|
+
# 翻訳を実行するクラス
|
10
|
+
# JpTranslatorFromGptを使用して翻訳を行う
|
11
|
+
class Performer
|
12
|
+
# @param [Boolean] output_logs ログを出力するか
|
13
|
+
# @param [Array<String>] except_words 翻訳しない単語
|
14
|
+
# @param [String] exchange_language どの言語に翻訳するか
|
15
|
+
# @param [Boolean] display_help ヘルプを表示するか
|
16
|
+
# @return [JpQuest::SNBT::Performer]
|
17
|
+
def initialize(output_logs: true, except_words: [], exchange_language: "japanese", display_help: true)
|
18
|
+
@translator = JpTranslatorFromGpt::Translator.new(
|
19
|
+
output_logs: output_logs,
|
20
|
+
except_words: except_words,
|
21
|
+
exchange_language: exchange_language
|
22
|
+
)
|
23
|
+
@reader = nil
|
24
|
+
@writer = nil
|
25
|
+
@progress_bar = nil
|
26
|
+
|
27
|
+
JpQuest.help if display_help
|
28
|
+
end
|
29
|
+
|
30
|
+
# ファイルを翻訳して出力する
|
31
|
+
#
|
32
|
+
# @param [String] file_path ファイルのパス
|
33
|
+
# @return [void]
|
34
|
+
def perform(file_path)
|
35
|
+
file_path = File.expand_path(file_path)
|
36
|
+
validate_path(file_path)
|
37
|
+
|
38
|
+
@reader, @writer = JpQuest::SNBT::Reader.new(file_path), JpQuest::SNBT::Writer.new(file_path)
|
39
|
+
results = @reader.extract_all.flatten
|
40
|
+
@progress_bar = JpQuest.create_progress_bar(file_path, results.length)
|
41
|
+
|
42
|
+
results.each do |result|
|
43
|
+
result[:text] = @translator.translate(result[:text])
|
44
|
+
@writer.overwrites(result)
|
45
|
+
@progress_bar.increment
|
46
|
+
end
|
47
|
+
|
48
|
+
puts "Completed!"
|
49
|
+
end
|
50
|
+
|
51
|
+
# ディレクトリ内のファイルを翻訳して出力する
|
52
|
+
#
|
53
|
+
# @param [String] dir_path ディレクトリのパス
|
54
|
+
# @return [void]
|
55
|
+
def perform_directory(dir_path: "quests")
|
56
|
+
dir_path = File.expand_path(dir_path)
|
57
|
+
validate_path(dir_path)
|
58
|
+
|
59
|
+
# **でサブディレクトリも含めて取得
|
60
|
+
Dir.glob("#{dir_path}/**/*.snbt").each do |file_path|
|
61
|
+
perform(file_path)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# ファイルの存在を確認する
|
66
|
+
# 存在しない場合はPathNotFoundErrorを投げる
|
67
|
+
#
|
68
|
+
# @param [String] path ファイルのパス
|
69
|
+
# @return [void]
|
70
|
+
def validate_path(path)
|
71
|
+
path = File.expand_path(path)
|
72
|
+
raise JpQuest::PathNotFoundError.new(path) unless File.exist?(path)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../util/indent_helper"
|
4
|
+
require_relative "title_extractor"
|
5
|
+
require_relative "subtitle_extractor"
|
6
|
+
require_relative "description_extractor"
|
7
|
+
|
8
|
+
module JpQuest
|
9
|
+
module SNBT
|
10
|
+
# SNBT形式のファイルからタイトル、サブタイトル、説明を抽出するクラス
|
11
|
+
class Reader
|
12
|
+
include TitleExtractor
|
13
|
+
include SubtitleExtractor
|
14
|
+
include DescriptionExtractor
|
15
|
+
|
16
|
+
DESC_START_LENGTH = 14
|
17
|
+
DESC_END_LENGTH = -2
|
18
|
+
|
19
|
+
# @param [String] file_path ファイルのパス
|
20
|
+
# @return [JpQuest::SNBT::Reader]
|
21
|
+
def initialize(file_path)
|
22
|
+
@file_path = file_path
|
23
|
+
end
|
24
|
+
|
25
|
+
# タイトル、サブタイトル、説明を抽出する
|
26
|
+
#
|
27
|
+
# @return [Array<Array<Hash>>] タイトル、サブタイトル、説明の配列
|
28
|
+
def extract_all
|
29
|
+
titles = extract_titles
|
30
|
+
subtitles = extract_subtitles
|
31
|
+
descriptions = extract_descriptions
|
32
|
+
|
33
|
+
[titles, subtitles, descriptions]
|
34
|
+
end
|
35
|
+
|
36
|
+
# タイトルを抽出する
|
37
|
+
#
|
38
|
+
# @return [Array<Hash>] タイトル、行番号、インデントの配列
|
39
|
+
def extract_titles
|
40
|
+
super(@file_path)
|
41
|
+
end
|
42
|
+
|
43
|
+
# サブタイトルを抽出する
|
44
|
+
#
|
45
|
+
# @return [Array<Hash>] サブタイトル、行番号、インデントの配列
|
46
|
+
def extract_subtitles
|
47
|
+
super(@file_path)
|
48
|
+
end
|
49
|
+
|
50
|
+
# 説明を抽出する
|
51
|
+
#
|
52
|
+
# @return [Array<Hash>] 説明、開始行、終了行、インデントの配列
|
53
|
+
def extract_descriptions
|
54
|
+
super(@file_path)
|
55
|
+
end
|
56
|
+
|
57
|
+
# title: "some title"のような形式から、"some title"を抽出する
|
58
|
+
# 説明の場合は、description: ["some description"]のような形式から、"some description"を抽出する
|
59
|
+
#
|
60
|
+
# @param [String] line 行
|
61
|
+
# @param [Boolean] is_desc 説明かどうか
|
62
|
+
# @return [String] タイトル or サブタイトル or 説明
|
63
|
+
def extract_oneline(line, is_desc: false)
|
64
|
+
stripped_line = line.strip
|
65
|
+
return stripped_line.split(":", 2)[1] unless is_desc
|
66
|
+
|
67
|
+
if oneline_description?(line)
|
68
|
+
stripped_line[DESC_START_LENGTH..DESC_END_LENGTH]
|
69
|
+
elsif start_of?(line, key: :description)
|
70
|
+
stripped_line.split("[", 2)[1]
|
71
|
+
else
|
72
|
+
stripped_line.split("]", 2)[0]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# 1行の説明かどうか
|
77
|
+
#
|
78
|
+
# @param [String] line 行
|
79
|
+
# @return [Boolean]
|
80
|
+
def oneline_description?(line)
|
81
|
+
stripped_line = line.strip
|
82
|
+
start_of?(line, key: :description) && stripped_line.end_with?("]")
|
83
|
+
end
|
84
|
+
|
85
|
+
# どのコンテンツの開始行か
|
86
|
+
#
|
87
|
+
# @param [String] line 行
|
88
|
+
# @param [Symbol] key コンテンツの種類
|
89
|
+
# @return [Boolean]
|
90
|
+
def start_of?(line, key:)
|
91
|
+
stripped_line = line.strip
|
92
|
+
sections = {
|
93
|
+
title: "title:",
|
94
|
+
subtitle: "subtitle:",
|
95
|
+
description: "description: ["
|
96
|
+
}
|
97
|
+
|
98
|
+
stripped_line.start_with?(sections[key])
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative "../util/indent_helper"
|
2
|
+
|
3
|
+
module JpQuest
|
4
|
+
module SNBT
|
5
|
+
# SNBT形式のファイルからsubtitle: "some subtitle"を抽出するモジュール
|
6
|
+
module SubtitleExtractor
|
7
|
+
include IndentHelper
|
8
|
+
|
9
|
+
# subtitle: "some subtitle"を抽出する
|
10
|
+
#
|
11
|
+
# @param [String] file_path ファイルのパス
|
12
|
+
# @return [Array<Hash>] サブタイトルと行番号の配列
|
13
|
+
def extract_subtitles(file_path)
|
14
|
+
subtitles = []
|
15
|
+
lines = File.readlines(file_path)
|
16
|
+
lines.each_with_index do |line, index|
|
17
|
+
next unless start_of?(line, key: :subtitle)
|
18
|
+
|
19
|
+
subtitles << {
|
20
|
+
type: :subtitle,
|
21
|
+
text: extract_oneline(line),
|
22
|
+
start_line: index,
|
23
|
+
end_line: index,
|
24
|
+
indent: count_indent(line)
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
subtitles
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative "../util/indent_helper"
|
2
|
+
|
3
|
+
module JpQuest
|
4
|
+
module SNBT
|
5
|
+
# SNBT形式のファイルからtitle: "some title"を抽出するモジュール
|
6
|
+
module TitleExtractor
|
7
|
+
include IndentHelper
|
8
|
+
|
9
|
+
# title: "some title"を抽出する
|
10
|
+
#
|
11
|
+
# @param [String] file_path ファイルのパス
|
12
|
+
# @return [Array<Hash>] タイトルと行番号の配列
|
13
|
+
def extract_titles(file_path)
|
14
|
+
titles = []
|
15
|
+
lines = File.readlines(file_path)
|
16
|
+
lines.each_with_index do |line, index|
|
17
|
+
next unless start_of?(line, key: :title)
|
18
|
+
|
19
|
+
titles << {
|
20
|
+
type: :title,
|
21
|
+
text: extract_oneline(line),
|
22
|
+
start_line: index,
|
23
|
+
end_line: index,
|
24
|
+
indent: count_indent(line)
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
titles
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require_relative "../util/error"
|
2
|
+
require_relative "../util/indent_helper"
|
3
|
+
require_relative "formatter"
|
4
|
+
|
5
|
+
module JpQuest
|
6
|
+
module SNBT
|
7
|
+
# 翻訳された内容を整形して出力するクラス
|
8
|
+
class Writer
|
9
|
+
include IndentHelper
|
10
|
+
|
11
|
+
# @param [String] file_path ファイルのパス
|
12
|
+
# @return [JpQuest::SNBT::Writer]
|
13
|
+
def initialize(file_path)
|
14
|
+
@input_file_path = file_path
|
15
|
+
# questsとすると、quests.snbtも変換されてしまうので、quests/とする
|
16
|
+
@output_file_path = file_path.gsub("quests/", "output/quests/")
|
17
|
+
@formatter = JpQuest::SNBT::Formatter.new
|
18
|
+
end
|
19
|
+
|
20
|
+
# 翻訳された内容でoutput_file_pathを上書きする
|
21
|
+
#
|
22
|
+
# @param [Hash] translated_contents 翻訳された内容
|
23
|
+
# @return [void]
|
24
|
+
def overwrites(translated_contents)
|
25
|
+
# ディレクトリが存在しない場合は作成
|
26
|
+
FileUtils.mkdir_p(File.dirname(@output_file_path))
|
27
|
+
|
28
|
+
# 一度上書きしている場合は上書き後のファイルを読み込む
|
29
|
+
# 常に上書き前のファイルを読み込むと、前回の上書きが消えてしまう
|
30
|
+
lines = File.readlines(first_overwrite? ? @input_file_path : @output_file_path)
|
31
|
+
formatted_lines = overwrite_lines(lines, translated_contents)
|
32
|
+
|
33
|
+
File.open(@output_file_path, "w") do |file|
|
34
|
+
file.puts formatted_lines
|
35
|
+
end
|
36
|
+
|
37
|
+
handle_line_count_error(@output_file_path, lines.length)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# 行を上書きする
|
43
|
+
#
|
44
|
+
# @param [Array<String>] lines 行
|
45
|
+
# @param [Hash] content コンテンツ
|
46
|
+
# @return [Array<String>] 上書きされた行
|
47
|
+
def overwrite_lines(lines, content)
|
48
|
+
indent = create_indent(content[:indent])
|
49
|
+
overwritable_lines = @formatter.format_overwritable_lines(content, indent)
|
50
|
+
lines[content[:start_line]..content[:end_line]] = overwritable_lines.split("\n")
|
51
|
+
lines
|
52
|
+
end
|
53
|
+
|
54
|
+
# 最初の上書きかどうか
|
55
|
+
#
|
56
|
+
# @return [Boolean] 最初の上書きかどうか
|
57
|
+
def first_overwrite?
|
58
|
+
!File.exist?(@output_file_path)
|
59
|
+
end
|
60
|
+
|
61
|
+
# 翻訳前と翻訳後の行数が異なる場合はエラーを発生させる
|
62
|
+
#
|
63
|
+
# @param [String] output_file_path 出力ファイルのパス
|
64
|
+
# @param [Integer] before_line_count 翻訳前の行数
|
65
|
+
# @return [void]
|
66
|
+
def handle_line_count_error(output_file_path, before_line_count)
|
67
|
+
after_line_count = File.readlines(output_file_path).length
|
68
|
+
return if before_line_count == after_line_count
|
69
|
+
|
70
|
+
raise JpQuest::InvalidLineCountError.new(before_line_count, after_line_count)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -36,7 +36,7 @@ module JpQuest
|
|
36
36
|
Translator for #{green(".snbt")} files.
|
37
37
|
If you want to translate to other languages than Japanese,
|
38
38
|
please add the #{green("exchange_language")} option during initialization.
|
39
|
-
Example: #{green("JpQuest::Performer.new(exchange_language: \"English\")")}
|
39
|
+
Example: #{green("JpQuest::SNBT::Performer.new(exchange_language: \"English\")")}
|
40
40
|
INTRO
|
41
41
|
end
|
42
42
|
|
@@ -52,7 +52,7 @@ module JpQuest
|
|
52
52
|
4. Add "quests" directory to your project
|
53
53
|
5. #{green("gem install jp_quest")} or #{green("gem \"jp_quest\"")}
|
54
54
|
6. Add #{green("require \"jp_quest\"")}
|
55
|
-
7. Add #{green("jp_quest = JpQuest::Performer.new")}
|
55
|
+
7. Add #{green("jp_quest = JpQuest::SNBT::Performer.new")}
|
56
56
|
8. #{green("jp_quest.perform(\"file_path\")")} or
|
57
57
|
#{green("jp_quest.perform_directory(dir_path: \"dir_path\")")}
|
58
58
|
9. Check "output" directory
|