jp_quest 0.2.1 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d0c36a1f3e9e85ef6e690ec96ddbb36391efe55d9d996490a5905c0d7dc98c15
4
- data.tar.gz: 66555ea8f531ae8ac001f97d852b4f38797e4e3d38db294f1804fdbc76cb901b
3
+ metadata.gz: 8b60021d6bf3d6a4f83ca95bd2f82bbb807e6a4fcd7a565f4cc8522c1be7c5f2
4
+ data.tar.gz: afd68be002b732797ca2fa25d2ce11f0eb511ad861d81a31d7957735a8153cea
5
5
  SHA512:
6
- metadata.gz: a3011529e8f7a2b4808223fd3bcfaf4c078f56ca637748d3fbd33eb226aebf07cfafd2d2654591ea56ca5a2e6069e0ecc5d691db72d4570465d5763a5ff4169a
7
- data.tar.gz: 63ee1e3a2ee419b72654a2cd87fec57e1e8eb2cbf26c93114347de58fa5e0874d5b9c91e833fab740b84c40216751d48d1e30bf552ba3253cf785f4ed51586a4
6
+ metadata.gz: caf15b2caa051d76815762bec0d5417d9bbf1067352549f59e0fa5031d69b4194249384f5a56473c79fd21fc10370434fbd2b04b560ee34ef1ad7cf780cf9d4c
7
+ data.tar.gz: c50ffae11c5bf0e857f64c67ff8e570f990ad95c1b8bb52f4e41cb49eda525161cc2cd883db314c972e1820bcb9b2027cb0ce3127dd29fae104861a5baa2b0b6
data/CHANGELOG.md CHANGED
@@ -19,4 +19,16 @@
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の翻訳機能を追加しやすいように、モジュールの構造を変更
31
+
32
+ ## [0.3.1] - 2024-10/25
33
+
34
+ - 不要な空行が追加されるバグを修正
data/README.md CHANGED
@@ -7,7 +7,7 @@ Can always get help with `JpQuest.help`
7
7
 
8
8
  #### Example
9
9
 
10
- `JpQuest::Performer.new(exchange_language: "English")`
10
+ `JpQuest::SNBT::Performer.new(exchange_language: "English")`
11
11
 
12
12
  ## Steps
13
13
 
data/dist/example.rb CHANGED
@@ -1,8 +1,9 @@
1
1
  require "jp_quest"
2
2
 
3
- performer = JpQuest::Performer.new
3
+ performer = JpQuest::SNBT::Performer.new
4
4
 
5
- # file_path = "some.snbt"
6
- # performer.perform(file_path)
5
+ file_path = "dist/quests/chapters/medium_eyes.snbt"
6
+ # file_path = "dist/dawncraft.snbt"
7
+ performer.perform(file_path)
7
8
 
8
- performer.perform_directory(dir_path: "dist/quests")
9
+ # performer.perform_directory
@@ -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,196 @@
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 = adjust_line_length(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
+ # 行数をstart_line~end_lineと一致させる
32
+ #
33
+ # @param [Hash] content コンテンツ
34
+ # @return [void]
35
+ def adjust_line_length(content)
36
+ required_lines = extract_required_line_counts(content)
37
+ lines = content[:text].split("\n")
38
+
39
+ delete_over_lines(lines, required_lines)
40
+ add_missing_lines(lines, required_lines, content[:indent])
41
+
42
+ lines
43
+ end
44
+
45
+ private
46
+
47
+ # 不要な文字を削除する
48
+ #
49
+ # @param [String] lines 行
50
+ # @param [Hash] content コンテンツ
51
+ # @return [Array<String>] 不要な文字を削除した行
52
+ def prepare_lines_for_snbt(lines, content)
53
+ lines.map! { |line| delete_unwanted_symbols(line) }
54
+ lines.map!(&:strip) unless content[:type] == :description
55
+ lines
56
+ end
57
+
58
+ # SNBT形式に変換しやすい形に整形
59
+ #
60
+ # @param [Array<String>] lines 行
61
+ # @param [String] indent インデント
62
+ # @param [Hash] content コンテンツ
63
+ # @return [String] SNBT形式に変換しやすく整形した行
64
+ def format_lines(lines, indent, content)
65
+ if lines.length == 1
66
+ content[:type] == :description ? "[#{lines[0].strip}]" : lines[0].strip.to_s
67
+ else
68
+ # [
69
+ # "Hello"
70
+ # "World"
71
+ # ]
72
+ mid_indent = middle_indent(content[:indent])
73
+ lines = lines.map { |line| "#{mid_indent}#{line.strip}" }
74
+ "[\n#{lines.join("\n")}\n#{indent}]"
75
+ end
76
+ end
77
+
78
+ # 必要な行数を抽出
79
+ #
80
+ # @param [Hash] content コンテンツ
81
+ # @return [Integer] 必要な行数
82
+ def extract_required_line_counts(content)
83
+ # start_lineが1、end_lineが5の場合、必要な行数はブラケットを抜いて3行
84
+ # そのため、(end(5) - start(1)) + 1行 - ブラケット2行 = 3行となる
85
+ line_offset, without_brackets = 1, 2
86
+
87
+ (content[:end_line] - content[:start_line]) + line_offset - without_brackets
88
+ end
89
+
90
+ # 不要な行を削除
91
+ #
92
+ # @param [Array<String>] lines 行
93
+ # @param [Integer] required_lines 必要な行数
94
+ # @return [void]
95
+ def delete_over_lines(lines, required_lines)
96
+ return unless lines.length > required_lines
97
+
98
+ gap_length = lines.length - required_lines
99
+ gap_length.times do
100
+ index = lines.index("")
101
+ lines.delete_at(index) if index
102
+ end
103
+ end
104
+
105
+ # 不足している行を追加
106
+ #
107
+ # @param [Array<String>] lines 行
108
+ # @param [Integer] required_lines 必要な行数
109
+ # @param [String] indent インデント
110
+ # @return [void]
111
+ def add_missing_lines(lines, required_lines, indent)
112
+ return unless lines.length < required_lines
113
+
114
+ while lines.length < required_lines
115
+ lines << empty_middle_line(indent)
116
+ end
117
+ end
118
+
119
+ # 中間行の空行を作成
120
+ #
121
+ # @return [String] 空行
122
+ def empty_middle_line(indent)
123
+ middle_indent(indent).to_s
124
+ end
125
+
126
+ # 不要な記号を削除
127
+ #
128
+ # @param [String] line 行
129
+ # @return [String] 不要な記号を削除した行
130
+ def delete_unwanted_symbols(line)
131
+ line = delete_backslash(line)
132
+ line = delete_semicolon(line)
133
+ line = delete_dup_quotes(line)
134
+ line = delete_jp_quotes(line)
135
+ delete_curved_quotes(line)
136
+ end
137
+
138
+ # 不要なバックスラッシュを削除
139
+ #
140
+ # @param [String] line 行
141
+ # @return [String] 不要なバックスラッシュを削除した行
142
+ def delete_backslash(line)
143
+ line.gsub("\\", "")
144
+ end
145
+
146
+ # 不要なセミコロンを削除
147
+ #
148
+ # @param [String] line 行
149
+ # @return [String] 不要なセミコロンを削除した行
150
+ def delete_semicolon(line)
151
+ line.gsub(";", "")
152
+ end
153
+
154
+ # 不要なダブルクオートを削除
155
+ #
156
+ # @param [String] line 行
157
+ # @return [String] 不要なダブルクオートを削除した行
158
+ def delete_dup_quotes(line)
159
+ # 行間にある余計なダブルクオートを削除するため、一度全てのダブルクオートを削除している
160
+ # 全て削除したあと、行頭、行末にダブルクオートを追加する
161
+ line = line.gsub('"', "")
162
+ line_start = /^(\s*)/
163
+ line = line.sub(line_start, "\"")
164
+ "#{line}\""
165
+ end
166
+
167
+ # 不要な鍵括弧を削除
168
+ #
169
+ # @param [String] line 行
170
+ # @return [String] 不要な鍵括弧を削除した行
171
+ def delete_jp_quotes(line)
172
+ # 「Hello」
173
+ deletable_reg = /「.*」/
174
+ return line unless line.match?(deletable_reg)
175
+
176
+ jp_quotes = [/「/, /」/]
177
+ jp_quotes.each { |quo| line = line.gsub(quo, "") }
178
+ line
179
+ end
180
+
181
+ # 不要な曲がった引用符を削除
182
+ #
183
+ # @param [String] line 行
184
+ # @return [String] 不要な曲がった引用符を削除した行
185
+ def delete_curved_quotes(line)
186
+ # “Hello”
187
+ deletable_reg = /“.*”/
188
+ return line unless line.match?(deletable_reg)
189
+
190
+ curved_quotes = [/“/, /”/]
191
+ curved_quotes.each { |quo| line = line.gsub(quo, "") }
192
+ line
193
+ end
194
+ end
195
+ end
196
+ 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