jekyll-chatgpt-translate 0.0.17 → 0.0.19
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/README.md +13 -0
- data/features/step_definitions/steps.rb +6 -10
- data/jekyll-chatgpt-translate.gemspec +1 -1
- data/lib/jekyll-chatgpt-translate/chatgpt.rb +3 -3
- data/lib/jekyll-chatgpt-translate/generator.rb +34 -32
- data/lib/jekyll-chatgpt-translate/plain.rb +10 -1
- data/lib/jekyll-chatgpt-translate/version.rb +1 -1
- data/test/test_generator.rb +6 -11
- data/test/test_plain.rb +13 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d7cc9cfc295b4eeb123b972094f4fa1c648a88f3df384a78b489b9b0bafbd0c1
|
4
|
+
data.tar.gz: 06cd12eabf0fbf6e77a64f52384609bcdc33edb8c6324aa4555de4f7fb275c99
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d0b55a94c132688afe28b9edbc4115570e6fd449b001bc606bf33c9d30712f2c1639fa8e0334652c0e8aa36b79e356f40845162e810e5b980f8b2dbcd7641746
|
7
|
+
data.tar.gz: e058ea19c7ffb630ab48bac0b433c8fde5f5b76d6087833cb2f7a70c04eaaca32f7273cacd881caf7b3b9355b5cb6a15f539060ff14bd3184baf5a6214b79914
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/glogin.svg)](http://badge.fury.io/rb/glogin)
|
1
2
|
<img src="logo.png" style="width:256px;"/>
|
2
3
|
|
3
4
|
[![rake](https://github.com/yegor256/jekyll-chatgpt-translate/actions/workflows/rake.yml/badge.svg)](https://github.com/yegor256/jekyll-chatgpt-translate/actions/workflows/rake.yml)
|
@@ -50,6 +51,8 @@ to get the URL of the page that was translated.
|
|
50
51
|
|
51
52
|
You can also use `{{ page.chatgpt-model }}`
|
52
53
|
inside both the original page and the translated one, to refer to the model of ChatGPT.
|
54
|
+
The presence of this attribute in the `{{ page }}` means that the
|
55
|
+
page was translated or the translated HTML was downloaded and placed into the `_site` directory.
|
53
56
|
|
54
57
|
## Options
|
55
58
|
|
@@ -62,6 +65,16 @@ Full list of options available to specify in `_config.yml`:
|
|
62
65
|
|
63
66
|
* `source` (optional) — is the ISO-839-1 code of the source language.
|
64
67
|
|
68
|
+
* `no_download` (optional) — if this attribute is present, the plugin won't try
|
69
|
+
to find HTML versions of translated pages in the Internet and won't try to
|
70
|
+
download them and place into the `_site` directory. Thus, your entire site
|
71
|
+
will have to be re-translated on every build (might be very ineffective if the site is big!)
|
72
|
+
|
73
|
+
* `min_chars` (optional) — minimum number of chars that must be present in
|
74
|
+
a paragraph in order for it to be feasible to go to ChatGPT. The robot
|
75
|
+
doesn't translate short paragraphs pretty enough. It's better to keep this
|
76
|
+
number big enough, to avoid silly translations. The default is 128.
|
77
|
+
|
65
78
|
* `layout` (optional) — is name of the file in `_layouts` directory, without the extension.
|
66
79
|
This layout will be specified for the pages generated by this plugin.
|
67
80
|
|
@@ -40,7 +40,7 @@ Given(/^I have a "([^"]*)" file with content:$/) do |file, text|
|
|
40
40
|
File.write(file, text.gsub('\\xFF', 0xFF.chr))
|
41
41
|
end
|
42
42
|
|
43
|
-
When(
|
43
|
+
When('I build Jekyll site') do
|
44
44
|
@stdout = `jekyll build`
|
45
45
|
@exitstatus = $CHILD_STATUS.exitstatus
|
46
46
|
end
|
@@ -59,20 +59,16 @@ Then('File {string} contains {string}') do |string, string2|
|
|
59
59
|
raise "The file \"#{string}\" doesn't contain \"#{string2}\":\n#{content}" unless content.include?(string2)
|
60
60
|
end
|
61
61
|
|
62
|
-
Then(
|
63
|
-
raise "STDOUT is not empty:\n#{@stdout}" unless @stdout == ''
|
64
|
-
end
|
65
|
-
|
66
|
-
Then(/^Exit code is zero$/) do
|
62
|
+
Then('Exit code is zero') do
|
67
63
|
raise "Non-zero exit #{@exitstatus}:\n#{@stdout}" unless @exitstatus.zero?
|
68
64
|
end
|
69
65
|
|
70
|
-
Then(
|
66
|
+
Then('Exit code is not zero') do
|
71
67
|
raise 'Zero exit code' if @exitstatus.zero?
|
72
68
|
end
|
73
69
|
|
74
|
-
When(
|
75
|
-
@stdout = `#{
|
70
|
+
When('I run bash with {string}') do |string|
|
71
|
+
@stdout = `#{string}`
|
76
72
|
@exitstatus = $CHILD_STATUS.exitstatus
|
77
73
|
end
|
78
74
|
|
@@ -81,7 +77,7 @@ When(/^I run bash with:$/) do |text|
|
|
81
77
|
@exitstatus = $CHILD_STATUS.exitstatus
|
82
78
|
end
|
83
79
|
|
84
|
-
When(
|
80
|
+
When('I copy this gem into temp dir') do
|
85
81
|
FileUtils.copy_entry(@cwd, File.join(@dir, 'jekyll-chatgpt-translate'))
|
86
82
|
end
|
87
83
|
|
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
|
|
28
28
|
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
|
29
29
|
s.required_ruby_version = '>= 2.6'
|
30
30
|
s.name = 'jekyll-chatgpt-translate'
|
31
|
-
s.version = '0.0.
|
31
|
+
s.version = '0.0.19'
|
32
32
|
s.license = 'MIT'
|
33
33
|
s.summary = 'Translate Jekyll Pages Through ChatGPT'
|
34
34
|
s.description = [
|
@@ -47,12 +47,12 @@ class GptTranslate::ChatGPT
|
|
47
47
|
@target = target
|
48
48
|
end
|
49
49
|
|
50
|
-
def translate(text)
|
50
|
+
def translate(text, min: 32)
|
51
51
|
text.split("\n\n").compact.map do |par|
|
52
|
-
if par.length
|
52
|
+
if par.length < min
|
53
53
|
Jekyll.logger.debug("Not translating this, b/c too short: \"#{par}\"")
|
54
54
|
par
|
55
|
-
elsif par !~ /^[[:alpha:]]/
|
55
|
+
elsif par !~ /^[[[:alpha:]]'"]/
|
56
56
|
Jekyll.logger.debug("Not translating this, b/c it's not a plain text: \"#{par}\"")
|
57
57
|
par
|
58
58
|
elsif @key.empty?
|
@@ -53,6 +53,7 @@ class GptTranslate::Generator < Jekyll::Generator
|
|
53
53
|
layout = config['layout'] || 'translated'
|
54
54
|
version = config['version'] || GptTranslate::VERSION
|
55
55
|
threshold = config['threshold'] || 1024
|
56
|
+
min_chars = config['min_chars'] || 128
|
56
57
|
start = Time.now
|
57
58
|
translated = 0
|
58
59
|
copied = 0
|
@@ -68,41 +69,42 @@ class GptTranslate::Generator < Jekyll::Generator
|
|
68
69
|
FileUtils.mkdir_p(File.dirname(path))
|
69
70
|
File.write(path, '') # in order to surpress warnings in Page ctor
|
70
71
|
dest = Jekyll::Page.new(site, site.source, File.dirname(path), File.basename(path)).destination(site.dest)
|
71
|
-
|
72
|
-
doc.data['chatgpt-model'] = model
|
73
|
-
if GptTranslate::Ping.new(site, link).found?(dest, version)
|
72
|
+
if config['no_download'].nil? && GptTranslate::Ping.new(site, link).found?(dest, version)
|
74
73
|
copied += 1
|
74
|
+
elsif translated >= threshold
|
75
75
|
next
|
76
|
+
else
|
77
|
+
gpt = GptTranslate::ChatGPT.new(
|
78
|
+
key,
|
79
|
+
model,
|
80
|
+
config['source'] || 'en',
|
81
|
+
lang
|
82
|
+
)
|
83
|
+
foreign = gpt.translate(plain, min: min_chars)
|
84
|
+
File.write(
|
85
|
+
path,
|
86
|
+
[
|
87
|
+
'---',
|
88
|
+
"layout: #{target['layout'] || layout}",
|
89
|
+
"title: #{doc['title'].to_json}",
|
90
|
+
"description: #{doc['description'].to_json}",
|
91
|
+
"permalink: #{link.to_json}",
|
92
|
+
"translated-original-url: #{doc.url.to_json}",
|
93
|
+
"translated-language: #{lang.to_json}",
|
94
|
+
"chatgpt-model: #{model.to_json}",
|
95
|
+
'---',
|
96
|
+
'',
|
97
|
+
foreign,
|
98
|
+
'',
|
99
|
+
"#{marker} on #{Time.now.strftime('%Y-%m-%d at %H:%M')}\n{: .jekyll-chatgpt-translate}"
|
100
|
+
].join("\n")
|
101
|
+
)
|
102
|
+
site.pages << Jekyll::Page.new(site, site.source, File.dirname(path), File.basename(path))
|
103
|
+
translated += 1
|
104
|
+
Jekyll.logger.info("Translated via ChatGPT: #{path} (#{File.size(path)} bytes)")
|
76
105
|
end
|
77
|
-
|
78
|
-
|
79
|
-
key,
|
80
|
-
model,
|
81
|
-
config['source'] || 'en',
|
82
|
-
lang
|
83
|
-
)
|
84
|
-
foreign = gpt.translate(plain)
|
85
|
-
File.write(
|
86
|
-
path,
|
87
|
-
[
|
88
|
-
'---',
|
89
|
-
"layout: #{target['layout'] || layout}",
|
90
|
-
"title: #{doc['title'].to_json}",
|
91
|
-
"description: #{doc['description'].to_json}",
|
92
|
-
"permalink: #{link.to_json}",
|
93
|
-
"translated-original-url: #{doc.url.to_json}",
|
94
|
-
"translated-language: #{lang.to_json}",
|
95
|
-
"chatgpt-model: #{model.to_json}",
|
96
|
-
'---',
|
97
|
-
'',
|
98
|
-
foreign,
|
99
|
-
'',
|
100
|
-
"#{marker} on #{Time.now.strftime('%d/%m/%Y %H:%M')}\n{: .jekyll-chatgpt-translate}"
|
101
|
-
].join("\n")
|
102
|
-
)
|
103
|
-
site.pages << Jekyll::Page.new(site, site.source, File.dirname(path), File.basename(path))
|
104
|
-
translated += 1
|
105
|
-
Jekyll.logger.info("Translated via ChatGPT: #{path} (#{File.size(path)} bytes)")
|
106
|
+
doc.data["translated-#{lang}-url"] = link
|
107
|
+
doc.data['chatgpt-model'] = model
|
106
108
|
end
|
107
109
|
end
|
108
110
|
Jekyll.logger.info("#{translated} pages translated and #{copied} pages copied in #{(Time.now - start).round(2)}s")
|
@@ -39,7 +39,7 @@ class GptTranslate::Plain
|
|
39
39
|
|
40
40
|
def to_s
|
41
41
|
# To turn compact lists into proper lists
|
42
|
-
@markdown.gsub(/([^\n])\n(\s*\*)/, "\\1\n\n\\2").split(/\n{2,}/).compact.map do |par|
|
42
|
+
@markdown.gsub(/([^\n])\n(\s*\* )/, "\\1\n\n\\2").split(/\n{2,}/).compact.map do |par|
|
43
43
|
par.strip!
|
44
44
|
# Liquid tags are removed, but this implementation is primitive
|
45
45
|
# Seehttps://stackoverflow.com/questions/
|
@@ -55,6 +55,7 @@ class GptTranslate::Plain
|
|
55
55
|
end
|
56
56
|
|
57
57
|
# Markdown to pain text.
|
58
|
+
# Motivated by https://github.com/vmg/redcarpet/blob/master/lib/redcarpet/render_strip.rb
|
58
59
|
class Strip < Redcarpet::Render::Base
|
59
60
|
%i[
|
60
61
|
block_code block_quote
|
@@ -71,6 +72,10 @@ class GptTranslate::Plain
|
|
71
72
|
end
|
72
73
|
end
|
73
74
|
|
75
|
+
def header(text, level)
|
76
|
+
"#{'#' * level} #{text}"
|
77
|
+
end
|
78
|
+
|
74
79
|
def codespan(content)
|
75
80
|
if content.start_with?("\n")
|
76
81
|
"```#{content}```"
|
@@ -81,6 +86,10 @@ class GptTranslate::Plain
|
|
81
86
|
end
|
82
87
|
end
|
83
88
|
|
89
|
+
def image(link, title, alt)
|
90
|
+
"![#{alt}](#{link} \"#{title}\")"
|
91
|
+
end
|
92
|
+
|
84
93
|
def raw_html(content)
|
85
94
|
content
|
86
95
|
end
|
data/test/test_generator.rb
CHANGED
@@ -75,28 +75,23 @@ class GptTranslate::GeneratorTest < Minitest::Test
|
|
75
75
|
end
|
76
76
|
|
77
77
|
class FakeDocument
|
78
|
+
attr_reader :data
|
79
|
+
|
78
80
|
def initialize(path)
|
79
81
|
@path = path
|
82
|
+
@data = { 'date' => Time.now, 'title' => 'Hello!' }
|
80
83
|
end
|
81
84
|
|
82
85
|
def content
|
83
86
|
'Hello, world!'
|
84
87
|
end
|
85
88
|
|
86
|
-
def
|
87
|
-
|
89
|
+
def []=(key, value)
|
90
|
+
@data[key] = value
|
88
91
|
end
|
89
92
|
|
90
|
-
def []=(key, value); end
|
91
|
-
|
92
93
|
def [](key)
|
93
|
-
|
94
|
-
Time.now
|
95
|
-
elsif key == 'title'
|
96
|
-
'Hello!'
|
97
|
-
else
|
98
|
-
''
|
99
|
-
end
|
94
|
+
@data[key] || ''
|
100
95
|
end
|
101
96
|
|
102
97
|
def relative_path
|
data/test/test_plain.rb
CHANGED
@@ -31,8 +31,10 @@ require_relative '../lib/jekyll-chatgpt-translate/plain'
|
|
31
31
|
# License:: MIT
|
32
32
|
class GptTranslate::PlainTest < Minitest::Test
|
33
33
|
def test_simple_map
|
34
|
-
assert_equal('Hello, world!', GptTranslate::Plain.new(
|
34
|
+
assert_equal('Hello, world!', GptTranslate::Plain.new("Hello,\n**world**!").to_s)
|
35
|
+
assert_equal('Hello, world!', GptTranslate::Plain.new("Hello,\n[world](/x.html)!").to_s)
|
35
36
|
assert_equal('Hello, Jeff!', GptTranslate::Plain.new('Hello, _Jeff_!').to_s)
|
37
|
+
# assert_equal('Hello, Walter!', GptTranslate::Plain.new('Hello, ~Walter~!').to_s)
|
36
38
|
assert_equal("Hi\n\nBye", GptTranslate::Plain.new(" Hi\n\nBye\n\n\n").to_s)
|
37
39
|
assert_equal('Hi, dude!', GptTranslate::Plain.new(" Hi,\ndude!\n").to_s)
|
38
40
|
end
|
@@ -83,6 +85,16 @@ class GptTranslate::PlainTest < Minitest::Test
|
|
83
85
|
)
|
84
86
|
end
|
85
87
|
|
88
|
+
def test_titles
|
89
|
+
assert_equal('# Hello', GptTranslate::Plain.new('# Hello').to_s)
|
90
|
+
assert_equal('## Hello', GptTranslate::Plain.new('## Hello').to_s)
|
91
|
+
assert_equal('### Hello', GptTranslate::Plain.new('### Hello').to_s)
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_image
|
95
|
+
assert_equal('![alt](a.png "hello")', GptTranslate::Plain.new('![alt](a.png "hello")').to_s)
|
96
|
+
end
|
97
|
+
|
86
98
|
def test_html
|
87
99
|
assert_equal(
|
88
100
|
'This is picture: <img src="a"/>!',
|