jp_quest 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|