jekyll-chatgpt-translate 0.0.30 → 0.0.31

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: 5ac852a5c56511f0e7500c8d907058b3b90f94a976446603fe852ba57132253e
4
- data.tar.gz: da8e37f819dcbbf5d907bf343d8dee167b36aedeef3863f68ca18bacf0783f11
3
+ metadata.gz: 8c50e5ce734d7a12ddcedbbcc4602453d5c0a7e78352a6e12bfbe04abfcf149e
4
+ data.tar.gz: 66f6a5668e0d37fd32a1f9573e34036b3155cf864238afb48116c8be4cd19e64
5
5
  SHA512:
6
- metadata.gz: 43e2cf29a74222c71c645323fbce0fe9ab5f2a27198c558bc0aa3bbab8620c48d794beb97f7e6a7e5898daf47227ab2ed0ea31b4bf92c098334a082d9c6d2f1f
7
- data.tar.gz: e14939086f28a2a1d865e3332e738f274f2ea18d673599509b5288558ad3856a5e1f67f9787ad4ac57d388854519adf9e125b2583bb5017e55304a2334480324
6
+ metadata.gz: b5adeb2316daff862f639e9318f5636d3651c69ea5fd50c42c3ddc86e13a7ac97406491fe7f0acf5bfe5d0550135a0568abeed790d1b70ccb3a593a89fc279b6
7
+ data.tar.gz: cf233bb2b67710883367515aaffffe4304d4c7f2b4c9571e276ed1323c90793bbddef1045067d5e84ca04dbb93fb946614bb5d05bbe71571bbfc589011af3c66
data/.gitignore CHANGED
@@ -3,4 +3,4 @@ Gemfile.lock
3
3
  .bundle/
4
4
  .DS_Store
5
5
  coverage/
6
- _chatgpt-translated/
6
+ _chatgpt-translate/
data/Gemfile CHANGED
@@ -29,7 +29,7 @@ gem 'cucumber', '8.0.0', require: false
29
29
  gem 'kramdown-parser-gfm', '1.1.0', require: false
30
30
  gem 'minitest', '5.19.0', require: false
31
31
  gem 'rake', '13.0.6', require: false
32
- gem 'rubocop', '1.56.0', require: false
32
+ gem 'rubocop', '1.56.2', require: false
33
33
  gem 'rubocop-rspec', '2.23.2', require: false
34
34
  gem 'simplecov', '0.22.0', require: false
35
35
  gem 'webmock', '3.18.1', require: false
data/README.md CHANGED
@@ -42,13 +42,13 @@ OpenAI API KEY must be set in `OPENAI_API_KEY` environment variable, otherwise
42
42
  the plugin will not do any translation and won't generate translated pages.
43
43
  You can get your key [here](https://help.openai.com/en/articles/4936850-where-do-i-find-my-secret-api-key).
44
44
 
45
- Inside the original page you can use `{{ page.translated-XX-url }}` in order to render the URL
45
+ Inside the original page you can use `{{ page.chatgpt-translate.urls[XX] }}` in order to render the URL
46
46
  of the translated page, where `XX` is the [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)
47
47
  code of the target language.
48
- Inside the translated page you can use `{{ page.translated-original-url }}` in order
48
+ Inside the translated page you can use `{{ page.chatgpt-translate.original-url }}` in order
49
49
  to get the URL of the page that was translated.
50
50
 
51
- You can also use `{{ page.chatgpt-model }}`
51
+ You can also use `{{ page.chatgpt-translate.model }}`
52
52
  inside both the original page and the translated one, to refer to the model of ChatGPT.
53
53
  The presence of this attribute in the `{{ page }}` means that the
54
54
  page was translated or the translated HTML was downloaded and placed into the `_site` directory.
@@ -80,7 +80,8 @@ Full list of options available to specify in `_config.yml`:
80
80
  number big enough, to avoid silly translations. The default is 128.
81
81
 
82
82
  * `layout` (optional) — is name of the file in `_layouts` directory, without the extension.
83
- This layout will be specified for the pages generated by this plugin.
83
+ This layout will be specified for the pages generated by this plugin.
84
+ The default value is `translated` (expecting you to have `_layouts/translated.html` file available).
84
85
 
85
86
  * `targets` (mandatory) — an array of target languages, each of which has the following attributes
86
87
 
@@ -100,6 +101,9 @@ This layout will be specified for the pages generated by this plugin.
100
101
  when the `version` is changed on another hand. By default, the version of
101
102
  this plugin will be used, unless you set your own value.
102
103
 
104
+ * `tmpdir` (optional) — the name of the directory where to keep temporary files,
105
+ `_chatgpt-translate` is the default value.
106
+
103
107
  ## How to Contribute
104
108
 
105
109
  Make a fork and then test it locally like this:
data/features/cli.feature CHANGED
@@ -22,19 +22,19 @@ Feature: Simple site building
22
22
  """
23
23
  And I have a "_layouts/default.html" file with content:
24
24
  """
25
- The Chinese: {{ page.translated-zh-url }}
26
- The French: {{ page.translated-fr-url }}
25
+ The Chinese: {{ page.chatgpt-translate.urls['zh'] }}
26
+ The French: {{ page.chatgpt-translate.urls['fr'] }}
27
27
  {{ content }}
28
28
  """
29
29
  And I have a "_layouts/chinese-translated.html" file with content:
30
30
  """
31
31
  Chinese: {{ content }}
32
- The original: {{ page.translated-original-url }}
32
+ The original: {{ page.chatgpt-translate.original-url }}
33
33
  """
34
34
  And I have a "_layouts/translated.html" file with content:
35
35
  """
36
36
  French: {{ content }}
37
- The original: {{ page.translated-original-url }}
37
+ The original: {{ page.chatgpt-translate.original-url }}
38
38
  """
39
39
  And I have a "_posts/2023-01-01-hello.md" file with content:
40
40
  """
@@ -46,9 +46,9 @@ Feature: Simple site building
46
46
  """
47
47
  Then I build Jekyll site
48
48
  And Exit code is zero
49
- And File "_chatgpt-translated/zh/2023-01-01-hello-zh.md" exists
50
- And File "_chatgpt-translated/zh/2023-01-01-hello-zh.md" contains "/2023-01-01-hello-chinese.html"
51
- And File "_chatgpt-translated/zh/2023-01-01-hello-zh.md" contains "translated-language: \"zh\""
49
+ And File "_chatgpt-translate/zh/2023-01-01-hello-zh.md" exists
50
+ And File "_chatgpt-translate/zh/2023-01-01-hello-zh.md" contains "/2023-01-01-hello-chinese.html"
51
+ And File "_chatgpt-translate/zh/2023-01-01-hello-zh.md" contains "language: \"zh\""
52
52
  And File "_site/2023/01/01/hello.html" exists
53
53
  And File "_site/2023/01/01/hello.html" contains "The Chinese: /2023-01-01-hello-chinese.html"
54
54
  And File "_site/2023-01-01-hello-chinese.html" exists
@@ -69,7 +69,7 @@ Feature: Simple site building
69
69
  layout: should-not-be-used
70
70
  targets:
71
71
  -
72
- language: en
72
+ language: ru
73
73
  permalink: about-me.html
74
74
  """
75
75
  And I have a "_posts/2023-01-01-hello.md" file with content:
@@ -77,12 +77,13 @@ Feature: Simple site building
77
77
  ---
78
78
  title: foo
79
79
  ---
80
- foo
80
+ see translated page: {{ page.chatgpt-translate.urls['ru'] }}
81
81
  """
82
82
  Then I build Jekyll site
83
83
  And Exit code is zero
84
- And Stdout contains "No need to translate, the page exists"
84
+ And Stdout contains "Re-translation not required, since version is empty"
85
85
  And File "_site/2023/01/01/hello.html" exists
86
+ And File "_site/2023/01/01/hello.html" contains "see translated page: /about-me.html"
86
87
  And File "_site/about-me.html" exists
87
88
  And File "_site/about-me.html" contains "Yegor Bugayenko"
88
89
 
@@ -125,3 +126,45 @@ Feature: Simple site building
125
126
  And File "_site/about-me.html" exists
126
127
  And File "_site/about-me.html" contains "foo-file-foo"
127
128
  And File "_site/boom.html" exists
129
+
130
+ Scenario: Simple translation with links to other pages
131
+ Given I have a "_config.yml" file with content:
132
+ """
133
+ url: https://www.yegor256.com
134
+ markdown: kramdown
135
+ plugins:
136
+ - jekyll-chatgpt-translate
137
+ chatgpt-translate:
138
+ source: en
139
+ api_key: "it-is-not-used, because EN to EN translation"
140
+ layout: default
141
+ targets:
142
+ -
143
+ language: en
144
+ permalink: :slug.html
145
+ """
146
+ And I have a "_layouts/default.html" file with content:
147
+ """
148
+ {{ content }}
149
+ """
150
+ And I have a "_posts/2023-01-01-hello.md" file with content:
151
+ """
152
+ ---
153
+ title: foo
154
+ ---
155
+ See {% post_url 2023-02-02-bye %}
156
+ """
157
+ And I have a "_posts/2023-02-02-bye.md" file with content:
158
+ """
159
+ ---
160
+ title: foo
161
+ ---
162
+ See {% post_url 2023-01-01-hello %}
163
+ """
164
+ Then I build Jekyll site
165
+ And Exit code is zero
166
+ And Stdout contains "The page is absent, need to translate"
167
+ And File "_site/2023/01/01/hello.html" exists
168
+ And File "_site/2023/01/01/hello.html" contains "/bye.html"
169
+ And File "_site/2023/02/02/bye.html" exists
170
+ And File "_site/2023/02/02/bye.html" contains "/hello.html"
@@ -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.30'
31
+ s.version = '0.0.31'
32
32
  s.license = 'MIT'
33
33
  s.summary = 'Translate Jekyll Pages Through ChatGPT'
34
34
  s.description = [
@@ -23,6 +23,7 @@
23
23
  # SOFTWARE.
24
24
 
25
25
  require 'jekyll'
26
+ require 'fileutils'
26
27
  require 'json'
27
28
  require_relative 'chatgpt'
28
29
  require_relative 'permalink'
@@ -44,7 +45,7 @@ class GptTranslate::Generator < Jekyll::Generator
44
45
  # Main plugin action, called by Jekyll-core
45
46
  def generate(site)
46
47
  config ||= site.config['chatgpt-translate'] || {}
47
- home = '_chatgpt-translated'
48
+ home = config['tmpdir'] || '_chatgpt-translate'
48
49
  key = api_key(config)
49
50
  if key.nil?
50
51
  Jekyll.logger.info('jekyll-chatgpt-translate requires OPENAI_API_KEY environment variable')
@@ -76,18 +77,34 @@ class GptTranslate::Generator < Jekyll::Generator
76
77
  "title: #{doc['title'].to_json}",
77
78
  "description: #{doc['description'].to_json}",
78
79
  "permalink: #{link.to_json}",
79
- "translated-original-url: #{doc.url.to_json}",
80
- "translated-language: #{lang.to_json}",
81
- "chatgpt-model: #{model.to_json}",
80
+ 'chatgpt-translate:',
81
+ " original-url: #{doc.url.to_json}",
82
+ " language: #{lang.to_json}",
83
+ " model: #{model.to_json}",
82
84
  '---'
83
85
  ].join("\n")
84
86
  )
85
- ping = GptTranslate::Ping.new(site, link)
86
- if config['no_download'].nil? && ping.found?(version.empty? ? '' : marker)
87
- copied += 1
88
- elsif translated >= threshold
89
- next
87
+ html = config['no_download'].nil? ? GptTranslate::Ping.new(site, link).download : nil
88
+ needed = false
89
+ if html.nil?
90
+ Jekyll.logger.info("The page is absent, need to translate #{link.inspect}")
91
+ needed = true
90
92
  else
93
+ copied += 1
94
+ site.static_files << DownloadedFile.new(site, link, html)
95
+ if version.empty?
96
+ Jekyll.logger.info("Re-translation not required, since version is empty: #{link.inspect}")
97
+ elsif html.include?(marker)
98
+ Jekyll.logger.info("No need to translate, the page exists at \
99
+ #{link.inspect} (#{html.split.count} words)")
100
+ else
101
+ Jekyll.logger.info("Re-translation required for #{link.inspect}")
102
+ needed = true
103
+ end
104
+ end
105
+ if translated >= threshold
106
+ Jekyll.logger.info("We are over the threshold: #{translated} > #{threshold}")
107
+ elsif needed
91
108
  gpt = GptTranslate::ChatGPT.new(
92
109
  key,
93
110
  model,
@@ -106,19 +123,39 @@ class GptTranslate::Generator < Jekyll::Generator
106
123
  mode: 'a+'
107
124
  )
108
125
  site.pages << Jekyll::Page.new(site, site.source, File.dirname(path), File.basename(path))
109
- site.static_files.delete_if { |f| f.is_a?(GptTranslate::Ping::DownloadedFile) && f.link == link }
126
+ site.static_files.delete_if { |f| f.is_a?(DownloadedFile) && f.link == link }
110
127
  translated += 1
111
128
  Jekyll.logger.info("Translated via ChatGPT \
112
129
  in #{(Time.now - start).round(2)}s: #{path} (#{File.size(path)} bytes)")
113
130
  end
114
- doc.data["translated-#{lang}-url"] = link
115
- doc.data['chatgpt-model'] = model
131
+ doc.data['chatgpt-translate'] ||= {}
132
+ doc.data['chatgpt-translate']['model'] ||= model
133
+ doc.data['chatgpt-translate']['urls'] ||= {}
134
+ doc.data['chatgpt-translate']['urls'][lang] = link
116
135
  end
117
136
  end
118
137
  Jekyll.logger.info("jekyll-chatgpt-translate #{GptTranslate::VERSION}: \
119
138
  #{translated} pages translated and #{copied} pages copied in #{(Time.now - start).round(2)}s")
120
139
  end
121
140
 
141
+ # The file we just downloaded.
142
+ class DownloadedFile < Jekyll::StaticFile
143
+ attr_reader :link
144
+
145
+ def initialize(site, link, html)
146
+ super(site, site.dest, '', link)
147
+ @html = html
148
+ @link = link
149
+ end
150
+
151
+ def write(_dest)
152
+ FileUtils.mkdir_p(File.dirname(path))
153
+ File.write(path, @html)
154
+ Jekyll.logger.info("Saved #{@html.split.count} words to #{path.inspect}")
155
+ true
156
+ end
157
+ end
158
+
122
159
  private
123
160
 
124
161
  # Try to find the KEY, either in the environment, a file, etc.
@@ -25,8 +25,6 @@
25
25
  require 'iri'
26
26
  require 'net/http'
27
27
  require 'uri'
28
- require 'jekyll'
29
- require 'fileutils'
30
28
  require_relative 'version'
31
29
 
32
30
  # see https://stackoverflow.com/a/6048451/187141
@@ -48,47 +46,20 @@ class GptTranslate::Ping
48
46
  @path = path
49
47
  end
50
48
 
51
- def found?(marker)
49
+ # Downloads the page from the Internet and returns HTML or NIL, if the page is absent
50
+ def download
52
51
  home = @site.config['url']
53
- return false if home.nil?
52
+ return nil if home.nil?
54
53
  uri = Iri.new(home).path(@path).to_s
54
+ html = nil
55
55
  begin
56
- before = Net::HTTP.get_response(URI(uri))
57
- if before.is_a?(Net::HTTPSuccess)
58
- html = before.body
59
- @site.static_files << DownloadedFile.new(@site, @path, html)
60
- if html.include?(marker)
61
- Jekyll.logger.info("No need to translate, the page exists at \
62
- #{uri.inspect} (#{html.split.count} words)")
63
- return true
64
- end
65
- Jekyll.logger.info("Re-translation required for #{uri.inspect}")
66
- else
67
- Jekyll.logger.info("The page is absent, will translate #{uri.inspect} (#{before.code})")
68
- end
69
- Jekyll.logger.debug("GET #{uri.inspect}: #{before.code}")
56
+ response = Net::HTTP.get_response(URI(uri))
57
+ html = response.body if response.is_a?(Net::HTTPSuccess)
58
+ Jekyll.logger.debug("GET #{uri.inspect}: #{response.code}")
70
59
  rescue Errno::ECONNREFUSED, Errno::EADDRNOTAVAIL => e
71
60
  Jekyll.logger.debug("Failed to ping #{uri.inspect}: #{e.message}")
72
61
  Jekyll.logger.info("The page is absent (#{e.class.name}): #{uri.inspect}")
73
62
  end
74
- false
75
- end
76
-
77
- # The file we just downloaded.
78
- class DownloadedFile < Jekyll::StaticFile
79
- attr_reader :link
80
-
81
- def initialize(site, link, html)
82
- super(site, site.dest, '', link)
83
- @html = html
84
- @link = link
85
- end
86
-
87
- def write(_dest)
88
- FileUtils.mkdir_p(File.dirname(path))
89
- File.write(path, @html)
90
- Jekyll.logger.info("Saved #{@html.split.count} words to #{path.inspect}")
91
- true
92
- end
63
+ html
93
64
  end
94
65
  end
@@ -121,7 +121,11 @@ class GptTranslate::Plain
121
121
  end
122
122
 
123
123
  def link(link, _title, content)
124
- "[#{content}](#{link})"
124
+ if !link.nil? && link.start_with?('/', 'https://', 'http://')
125
+ "[#{content}](#{link})"
126
+ else
127
+ content
128
+ end
125
129
  end
126
130
  end
127
131
  end
@@ -23,5 +23,5 @@
23
23
  # SOFTWARE.
24
24
 
25
25
  module GptTranslate
26
- VERSION = '0.0.30'
26
+ VERSION = '0.0.31'
27
27
  end
data/test/test_ping.rb CHANGED
@@ -38,24 +38,21 @@ class GptTranslate::PingTest < Minitest::Test
38
38
  stub_request(:any, 'https://www.yegor256.com/about-me.html').to_return(body: 'Hello!')
39
39
  site = GptTranslate::FakeSite.new({ 'url' => 'https://www.yegor256.com/' })
40
40
  ping = GptTranslate::Ping.new(site, '/about-me.html')
41
- assert(ping.found?(''))
42
- assert_equal(1, site.static_files.size)
41
+ assert(!ping.download.nil?)
43
42
  end
44
43
 
45
44
  def test_when_not_exists
46
45
  stub_request(:any, 'https://www.yegor256.com/absent.html').to_return(status: 404)
47
46
  site = GptTranslate::FakeSite.new({ 'url' => 'https://www.yegor256.com/' })
48
47
  ping = GptTranslate::Ping.new(site, '/absent.html')
49
- assert(!ping.found?(''))
50
- assert_equal(0, site.static_files.size)
48
+ assert(ping.download.nil?)
51
49
  end
52
50
 
53
51
  def test_wrong_address
54
52
  WebMock.allow_net_connect!
55
53
  site = GptTranslate::FakeSite.new({ 'url' => 'https://localhost:1/' })
56
54
  ping = GptTranslate::Ping.new(site, '/boom.html')
57
- assert(!ping.found?(''))
58
- assert_equal(0, site.static_files.size)
55
+ assert(ping.download.nil?)
59
56
  end
60
57
 
61
58
  def test_relative_path
data/test/test_plain.rb CHANGED
@@ -75,6 +75,14 @@ class GptTranslate::PlainTest < Minitest::Test
75
75
  'Hello, [dude](/a.html)!',
76
76
  GptTranslate::Plain.new('Hello, [dude](/a.html)!').to_s
77
77
  )
78
+ assert_equal(
79
+ 'Hello, dude!',
80
+ GptTranslate::Plain.new('Hello, [dude]()!').to_s
81
+ )
82
+ assert_equal(
83
+ 'Hello, dude!',
84
+ GptTranslate::Plain.new('Hello, [dude]({% post_url 2023-01-01-hello %})!').to_s
85
+ )
78
86
  end
79
87
 
80
88
  def test_code
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-chatgpt-translate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.30
4
+ version: 0.0.31
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-25 00:00:00.000000000 Z
11
+ date: 2023-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: iri