jekyll-chatgpt-translate 0.0.12 → 0.0.14

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed6617e3b8bf46db264f484e1286ea1f91295f4fb47512cb983a6fc59c7922df
4
- data.tar.gz: a0f6c744cd4bf2b2558d7b5568f1ca961a3f854e5264b9d64bb8b24249f03e3a
3
+ metadata.gz: 4b8a34c60ab2378b8dc26ab4b189ff3fa168cbb864c80db92a854d68b58def59
4
+ data.tar.gz: 3654fe32f201e8a155cd5f154129c24350333b6f2459cd86bb511c0acc22c0c1
5
5
  SHA512:
6
- metadata.gz: 2d58f41b76840e524e9f1d72c2a4816b33d9e57ad6b207f54baa226abf68ae6cca848cb8cce80cf1f4502a3ad9b52871db7f7708463bf4101fdbf8c21e5f99bb
7
- data.tar.gz: f85b41ad75176c9989a8a3715fd84485b3a2fcbe03e6cca879b7a201ac4b5745dda0aa16695f26cbaad1ec901b84c6837f983f7a04cee94aa26752d13ef41593
6
+ metadata.gz: ea02f9faba8ffedaa3e25bd428bde6aaba7a7a484bda745cc270a9f97f1a40211b776cff7d5a8c5d297854f107ba311b10dd5885bb6eff8de353f4a8aa9778d6
7
+ data.tar.gz: 6f3cc93df6fff8290f3a6d45bc980a9c5b273154a98ab7c18ddff1571c55dd8c2796e9ef965c3a0df72ff175c42ed54b72f4b4ecb5d2d8bb21864ae3b4aa0c7c
data/.gitignore CHANGED
@@ -2,4 +2,5 @@ Gemfile.lock
2
2
  *.gem
3
3
  .bundle/
4
4
  .DS_Store
5
- coverage/
5
+ coverage/
6
+ _chatgpt-translated/
data/features/cli.feature CHANGED
@@ -40,11 +40,12 @@ Feature: Simple site building
40
40
  Hello, world!
41
41
  """
42
42
  Then I build Jekyll site
43
- Then File "_chatgpt-translated/cn/2023-01-01-hello-cn.md" exists
44
- Then File "_site/2023/01/01/hello.html" exists
45
- Then File "_site/2023/01/01/hello.html" contains "The Chinese: /2023-01-01-hello-chinese.html"
46
- Then File "_site/2023-01-01-hello-chinese.html" exists
47
- Then File "_site/2023-01-01-hello-chinese.html" contains "The original: /2023/01/01/hello.html"
48
- Then File "_site/2023/hello-french.html" exists
43
+ And File "_chatgpt-translated/cn/2023-01-01-hello-cn.md" exists
44
+ And File "_chatgpt-translated/cn/2023-01-01-hello-cn.md" contains "/2023-01-01-hello-chinese.html"
45
+ And File "_site/2023/01/01/hello.html" exists
46
+ And File "_site/2023/01/01/hello.html" contains "The Chinese: /2023-01-01-hello-chinese.html"
47
+ And File "_site/2023-01-01-hello-chinese.html" exists
48
+ And File "_site/2023-01-01-hello-chinese.html" contains "The original: /2023/01/01/hello.html"
49
+ And File "_site/2023/hello-french.html" exists
49
50
  And Exit code is zero
50
51
 
@@ -50,10 +50,11 @@ Then(/^Stdout contains "([^"]*)"$/) do |txt|
50
50
  end
51
51
 
52
52
  Then(/^File "([^"]*)" exists$/) do |name|
53
- raise "The file \"#{name}\" is absent:\n#{`tree`}" unless File.exist?(name)
53
+ raise "The file \"#{name}\" is absent:\n#{`tree -s`}" unless File.exist?(name)
54
54
  end
55
55
 
56
56
  Then(/^File "([^"]*)" contains "([^"]*)"$/) do |name, text|
57
+ raise "The file \"#{name}\" is absent" unless File.exist?(name)
57
58
  content = File.read(name)
58
59
  raise "The file \"#{name}\" doesn't contain \"#{text}\":\n#{content}" unless content.include?(text)
59
60
  end
@@ -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.12'
31
+ s.version = '0.0.14'
32
32
  s.license = 'MIT'
33
33
  s.summary = 'Translate Jekyll Pages Through ChatGPT'
34
34
  s.description = [
@@ -92,17 +92,12 @@ through #{@model} in #{(Time.now - start).round(2)}s")
92
92
  end
93
93
 
94
94
  def prompt
95
- if (@source == 'ru') && (@target == 'en')
96
- 'Пожалуйста, переведи этот параграф на английский язык'
97
- elsif (@source == 'en') && (@target == 'ru')
98
- 'Please, translate this paragraph to Russian'
99
- else
100
- [
101
- 'Please, translate this paragraph from',
102
- ISO_639.find_by_code(@source),
103
- 'to',
104
- ISO_639.find_by_code(@target)
105
- ].join(' ')
106
- end
95
+ [
96
+ 'Please, translate this paragraph from',
97
+ ISO_639.find_by_code(@source),
98
+ 'to',
99
+ ISO_639.find_by_code(@target),
100
+ ', don\'t change proper nouns'
101
+ ].join(' ')
107
102
  end
108
103
  end
@@ -23,6 +23,7 @@
23
23
  # SOFTWARE.
24
24
 
25
25
  require 'jekyll'
26
+ require 'json'
26
27
  require_relative 'chatgpt'
27
28
  require_relative 'permalink'
28
29
  require_relative 'ping'
@@ -60,13 +61,19 @@ class GptTranslate::Generator < Jekyll::Generator
60
61
  plain = GptTranslate::Plain.new(doc.content).to_s
61
62
  config['targets'].each do |target|
62
63
  link = GptTranslate::Permalink.new(doc, target['permalink']).to_path
63
- next if GptTranslate::Ping.new(site, link).found?(doc.path, version)
64
64
  lang = target['language']
65
65
  raise 'Language must be defined for each target' if target.nil?
66
66
  if total >= threshold
67
67
  Jekyll.logger.info("Already generated #{total} pages, that's enough for today")
68
68
  break
69
69
  end
70
+ path = File.join(home, lang, doc.basename.gsub(/\.md$/, "-#{lang}.md"))
71
+ FileUtils.mkdir_p(File.dirname(path))
72
+ File.write(path, '') # in order to surpress warnings in Page ctor
73
+ dest = Jekyll::Page.new(site, site.source, File.dirname(path), File.basename(path)).destination(site.dest)
74
+ doc.data["translated-#{lang}-url"] = link
75
+ doc.data['chatgpt-model'] = model
76
+ next if GptTranslate::Ping.new(site, link).found?(dest, version)
70
77
  gpt = GptTranslate::ChatGPT.new(
71
78
  key,
72
79
  model,
@@ -74,17 +81,16 @@ class GptTranslate::Generator < Jekyll::Generator
74
81
  lang
75
82
  )
76
83
  translated = gpt.translate(plain)
77
- path = File.join(home, lang, doc.basename.gsub(/\.md$/, "-#{lang}.md"))
78
- FileUtils.mkdir_p(File.dirname(path))
79
84
  File.write(
80
85
  path,
81
86
  [
82
87
  '---',
83
88
  "layout: #{target['layout'] || layout}",
84
- "title: #{doc.data['title']}",
85
- "permalink: #{link}",
86
- "translated-original-url: #{doc.url}",
87
- "chatgpt-model: #{model}",
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
+ "chatgpt-model: #{model.to_json}",
88
94
  '---',
89
95
  '',
90
96
  translated,
@@ -92,8 +98,6 @@ class GptTranslate::Generator < Jekyll::Generator
92
98
  "#{marker}\n{: .jekyll-chatgpt-translate}"
93
99
  ].join("\n")
94
100
  )
95
- doc.data["translated-#{lang}-url"] = link
96
- doc.data['chatgpt-model'] = model
97
101
  site.pages << Jekyll::Page.new(site, site.source, File.dirname(path), File.basename(path))
98
102
  total += 1
99
103
  Jekyll.logger.info("Translated via ChatGPT: #{path}")
@@ -51,21 +51,26 @@ class GptTranslate::Ping
51
51
  home = @site.config['url']
52
52
  return false if home.nil?
53
53
  uri = Iri.new(home).path(@path)
54
- before = Net::HTTP.get_response(URI(uri.to_s))
55
- if before.is_a?(Net::HTTPSuccess)
56
- html = before.body
57
- if html.include?(marker)
58
- Jekyll.logger.info("No need to translate, the page exists at \
59
- #{uri} (#{html.split.count} words), saved to #{file}")
60
- FileUtils.mkdir_p(File.dirname(file))
61
- File.write(file, html)
62
- return true
54
+ begin
55
+ before = Net::HTTP.get_response(URI(uri.to_s))
56
+ if before.is_a?(Net::HTTPSuccess)
57
+ html = before.body
58
+ if html.include?(marker)
59
+ Jekyll.logger.info("No need to translate, the page exists at \
60
+ \"#{uri}\" (#{html.split.count} words), saved to \"#{file}\"")
61
+ FileUtils.mkdir_p(File.dirname(file))
62
+ File.write(file, html)
63
+ return true
64
+ end
65
+ Jekyll.logger.info("Re-translation required for \"#{uri}\"")
66
+ else
67
+ Jekyll.logger.info("The page is absent, will translate \"#{uri}\"")
63
68
  end
64
- Jekyll.logger.info("Re-translation required for #{uri}")
65
- else
66
- Jekyll.logger.info("The page is absent, will translate: #{uri}")
69
+ Jekyll.logger.debug("GET \"#{uri}\": #{before.code}")
70
+ rescue StandardError => e
71
+ Jekyll.logger.debug("Failed to ping \"#{uri}\": #{e.message}")
72
+ Jekyll.logger.info("The page is absent: \"#{uri}\"")
67
73
  end
68
- Jekyll.logger.debug("GET #{uri}: #{before.code}")
69
74
  false
70
75
  end
71
76
  end
@@ -38,28 +38,31 @@ class GptTranslate::Plain
38
38
  end
39
39
 
40
40
  def to_s
41
- @markdown.split(/\n{2,}/).compact.map do |par|
42
- par.gsub!("\n", ' ')
43
- par.gsub!(/\s{2,}/, ' ')
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|
43
+ # par.gsub!("\n", ' ')
44
+ par.gsub!("\t", ' ')
45
+ par.gsub!(/ {2,}/, ' ')
44
46
  # Liquid tags are removed, but this implementation is primitive
45
47
  # Seehttps://stackoverflow.com/questions/
46
48
  par.gsub!(/{{[^}]+}}/, '')
47
- par.gsub!(/{%[^%]+%}/, '')
49
+ par.gsub!(/{%.+?%}/, '')
50
+ par.gsub!(/<!--.+?-->/m, '')
48
51
  par.strip!
49
52
  Redcarpet::Markdown.new(Strip).render(par)
50
53
  end.join("\n\n").gsub(/\n{2,}/, "\n\n").strip
51
54
  end
52
55
 
53
- # To ignore/remove Liquid tags.
54
- class NullDrop < Liquid::Drop
55
- def method_missing(*)
56
- nil
57
- end
56
+ # # To ignore/remove Liquid tags.
57
+ # class NullDrop < Liquid::Drop
58
+ # def method_missing(*)
59
+ # nil
60
+ # end
58
61
 
59
- def respond_to_missing?(*)
60
- true
61
- end
62
- end
62
+ # def respond_to_missing?(*)
63
+ # true
64
+ # end
65
+ # end
63
66
 
64
67
  # Markdown to pain text.
65
68
  class Strip < Redcarpet::Render::Base
@@ -23,5 +23,5 @@
23
23
  # SOFTWARE.
24
24
 
25
25
  module GptTranslate
26
- VERSION = '0.0.12'
26
+ VERSION = '0.0.14'
27
27
  end
@@ -23,6 +23,8 @@
23
23
  # SOFTWARE.
24
24
 
25
25
  require 'minitest/autorun'
26
+ require 'tmpdir'
27
+ require 'webmock/minitest'
26
28
  require_relative '../lib/jekyll-chatgpt-translate/generator'
27
29
 
28
30
  # Generator test.
@@ -30,7 +32,123 @@ require_relative '../lib/jekyll-chatgpt-translate/generator'
30
32
  # Copyright:: Copyright (c) 2023 Yegor Bugayenko
31
33
  # License:: MIT
32
34
  class GptTranslate::GeneratorTest < Minitest::Test
35
+ class FakeSite
36
+ attr_reader :config
37
+
38
+ def initialize(config, doc)
39
+ @config = config
40
+ @doc = doc
41
+ end
42
+
43
+ def posts
44
+ FakePosts.new(@doc)
45
+ end
46
+
47
+ def pages
48
+ []
49
+ end
50
+
51
+ def permalink_style
52
+ ''
53
+ end
54
+
55
+ def frontmatter_defaults
56
+ Jekyll::FrontmatterDefaults.new(self)
57
+ end
58
+
59
+ def converters
60
+ [Jekyll::Converters::Markdown.new({ 'markdown_ext' => 'md' })]
61
+ end
62
+
63
+ def source
64
+ ''
65
+ end
66
+
67
+ def dest
68
+ ''
69
+ end
70
+
71
+ def in_theme_dir(base, _foo = nil, _bar = nil)
72
+ base
73
+ end
74
+
75
+ def in_dest_dir(*paths)
76
+ paths[0].dup
77
+ end
78
+ end
79
+
80
+ class FakeDocument
81
+ def initialize(path)
82
+ @path = path
83
+ end
84
+
85
+ def content
86
+ 'Hello, world!'
87
+ end
88
+
89
+ def data
90
+ {}
91
+ end
92
+
93
+ def []=(key, value); end
94
+
95
+ def [](key)
96
+ if key == 'date'
97
+ Time.now
98
+ elsif key == 'title'
99
+ 'Hello!'
100
+ else
101
+ ''
102
+ end
103
+ end
104
+
105
+ def relative_path
106
+ @path
107
+ end
108
+
109
+ def url
110
+ '2023-01-01-hello.html'
111
+ end
112
+
113
+ def basename
114
+ '2023-01-01-hello.md'
115
+ end
116
+ end
117
+
118
+ class FakePosts
119
+ attr_reader :config
120
+
121
+ def initialize(doc)
122
+ @doc = doc
123
+ end
124
+
125
+ def docs
126
+ [FakeDocument.new(@doc)]
127
+ end
128
+ end
129
+
33
130
  def test_simple_scenario
34
- # assert(stdout.include?('DEBUG'))
131
+ Dir.mktmpdir do |home|
132
+ post = File.join(home, '2023-01-01-hello.md')
133
+ File.write(post, "---\ntitle: Hello\n---\n\nHello, world!")
134
+ site = FakeSite.new(
135
+ {
136
+ 'url' => 'https://www.yegor256.com/',
137
+ 'chatgpt-translate' => {
138
+ 'targets' => [
139
+ {
140
+ 'language' => 'cn',
141
+ 'layout' => 'chinese',
142
+ 'permalink' => ':slug.html'
143
+ }
144
+ ]
145
+ }
146
+ },
147
+ FakeDocument.new({})
148
+ )
149
+ gen = GptTranslate::Generator.new
150
+ stub_request(:get, 'https://www.yegor256.com/.html').to_return(body: '')
151
+ gen.generate(site)
152
+ end
35
153
  end
36
154
  end
data/test/test_ping.rb CHANGED
@@ -59,6 +59,15 @@ class GptTranslate::PingTest < Minitest::Test
59
59
  end
60
60
  end
61
61
 
62
+ def test_wrong_address
63
+ WebMock.allow_net_connect!
64
+ site = FakeSite.new({ 'url' => 'https://localhost:1/' })
65
+ ping = GptTranslate::Ping.new(site, '/boom.html')
66
+ Tempfile.open do |f|
67
+ assert(!ping.found?(f, ''))
68
+ end
69
+ end
70
+
62
71
  def test_relative_path
63
72
  assert_raises do
64
73
  GptTranslate::Ping.new({}, '404.html')
data/test/test_plain.rb CHANGED
@@ -47,6 +47,20 @@ class GptTranslate::PlainTest < Minitest::Test
47
47
  )
48
48
  end
49
49
 
50
+ def test_ordered_list
51
+ assert_equal(
52
+ "first\n\nsecond\n\nthird",
53
+ GptTranslate::Plain.new("1. first\n\n2. second\n\n3. third").to_s
54
+ )
55
+ end
56
+
57
+ def test_compact_list
58
+ assert_equal(
59
+ "first\n\nsecond\n\nthird",
60
+ GptTranslate::Plain.new("* first\n* second\n* third").to_s
61
+ )
62
+ end
63
+
50
64
  def test_links
51
65
  assert_equal(
52
66
  'Hello, dude!',
@@ -89,5 +103,20 @@ class GptTranslate::PlainTest < Minitest::Test
89
103
  'Hello, !',
90
104
  GptTranslate::Plain.new('Hello, {% Java %}!').to_s
91
105
  )
106
+ assert_equal(
107
+ 'Hello, !',
108
+ GptTranslate::Plain.new('Hello, {% plantuml "width=50%" %}!').to_s
109
+ )
110
+ end
111
+
112
+ def test_html_comments
113
+ assert_equal(
114
+ 'Hello, !',
115
+ GptTranslate::Plain.new('Hello, <!-- Java -->!').to_s
116
+ )
117
+ assert_equal(
118
+ 'Hello, !',
119
+ GptTranslate::Plain.new("Hello, <!-- \nJava\n -->!").to_s
120
+ )
92
121
  end
93
122
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-chatgpt-translate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.12
4
+ version: 0.0.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko