i18n-ai 0.1.1 → 0.1.3

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: a4b8bb0bd9755345297a83d3c236a95fa9d68c1b432743f08cb48b9bc38fa03b
4
- data.tar.gz: 62f2a9fc7281367224041c3222191e345c15848757ee6e6cfc4905de2dc4156f
3
+ metadata.gz: 91c87df3579aa11f253f670664cbcf4721dc4145cb12740ab05f9f81a8fef913
4
+ data.tar.gz: 590b0626a6e5dee174d34ddd429154485a7345539bc398815851ca5c4bd50ea3
5
5
  SHA512:
6
- metadata.gz: 2a72a92c4f61419e2a76e9ad7df7086168128d24c5d6eafe9be395be4db948e6e6d06937d2db8d11356a85f295c53cf46952fb09eb1c7171eacfe4aa4e009d89
7
- data.tar.gz: 45997aa4a669cc795ee91841a6de94974ba782387ad1e55384700d3a407749b097079abe77aec6c2f505a42bf31adfdb01a145e8cc24dab52b3a7089b860044c
6
+ metadata.gz: '08ecd1e198abe8f8363ca6bc227a36a00335f6cc52024b7c5f6ef2013e6a0205a860bdcbc102c34b7953b0708d7f02bc7379946deb7f0b2e702314ffd3f6a143'
7
+ data.tar.gz: 4e3b1a31c6112457ed53f274d32cf98c21bae53bffcc69d8b91e2ec79403790a4090fbb69a37bc4e7cdd2f30ad99a232777160e29c0944750906c4b1d477483b
data/.rubocop.yml CHANGED
@@ -6,3 +6,15 @@ Style/StringLiterals:
6
6
 
7
7
  Style/StringLiteralsInInterpolation:
8
8
  EnforcedStyle: double_quotes
9
+
10
+ Metrics/BlockLength:
11
+ Exclude:
12
+ - 'spec/**/*_spec.rb'
13
+
14
+ Layout/LineLength:
15
+ Exclude:
16
+ - 'spec/**/*_spec.rb'
17
+
18
+ Naming/FileName:
19
+ Exclude:
20
+ - 'lib/i18n-ai.rb'
data/lib/i18n-ai.rb CHANGED
@@ -1,21 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "i18n-ai/version"
4
- require_relative "i18n-ai/railtie"
5
- require_relative "i18n-ai/configuration"
6
-
7
- module I18nAi
8
- class Error < StandardError; end
9
-
10
- class << self
11
- attr_writer :configuration
12
-
13
- def configuration
14
- @configuration ||= Configuration.new
15
- end
16
-
17
- def configure
18
- yield(configuration)
19
- end
20
- end
21
- end
3
+ require_relative "i18n_ai"
@@ -5,6 +5,7 @@ require_relative "base_client"
5
5
 
6
6
  module I18nAi
7
7
  module Clients
8
+ # The AnthropicClient class is responsible for interacting with the Anthropic API
8
9
  class AnthropicClient < BaseClient
9
10
  def initialize
10
11
  super
@@ -17,9 +18,7 @@ module I18nAi
17
18
  response = @client.messages(
18
19
  parameters: {
19
20
  model: @config[:model],
20
- messages: [
21
- { role: "user", content: content(locale, text) }
22
- ]
21
+ messages: [{ role: "user", content: content(locale, text) }]
23
22
  }
24
23
  )
25
24
 
@@ -2,13 +2,16 @@
2
2
 
3
3
  module I18nAi
4
4
  module Clients
5
+ # The BaseClient class serves as a base class for all AI client implementations
5
6
  class BaseClient
6
7
  def initialize
7
8
  @config = I18nAi.configuration.ai_settings
8
9
  end
9
10
 
10
11
  def content(locale, text_to_translate)
12
+ # rubocop:disable Layout/LineLength
11
13
  "Translate the following YAML content to #{locale.to_s.upcase} and make sure to retain the keys in english except the first key which is the 2 letter language code:\n\n#{text_to_translate}"
14
+ # rubocop:enable Layout/LineLength
12
15
  end
13
16
 
14
17
  def parse_response(response)
@@ -5,6 +5,7 @@ require_relative "base_client"
5
5
 
6
6
  module I18nAi
7
7
  module Clients
8
+ # The AnthropicClient class is responsible for interacting with the OpenAI API
8
9
  class OpenAiClient < BaseClient
9
10
  def initialize
10
11
  super
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module I18nAi
4
+ # Configuration class for I18nAi
4
5
  class Configuration
5
6
  attr_accessor :ai_settings, :generate_locales
6
7
 
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/railtie"
4
+ require "digest"
5
+
6
+ require_relative "clients/open_ai_client"
7
+ require_relative "clients/anthropic_client"
8
+
9
+ module I18nAi
10
+ # The Railtie class provides a way to integrate I18nAi into an application
11
+ class Railtie < Rails::Railtie
12
+ # Initialize the I18nAi middleware
13
+ class I18nAiMiddleware
14
+ def initialize(app)
15
+ @app = app
16
+ @client = configure_client
17
+ @last_checksum = nil
18
+ end
19
+
20
+ def call(env)
21
+ locales_file = locate_locales_file
22
+
23
+ if file_exists?(locales_file)
24
+ process_locales_file(locales_file)
25
+ else
26
+ log_file_not_found
27
+ end
28
+
29
+ @app.call(env)
30
+ end
31
+
32
+ private
33
+
34
+ def locate_locales_file
35
+ Rails.root.join("config", "locales", "en.yml")
36
+ end
37
+
38
+ def file_exists?(file)
39
+ File.exist?(file)
40
+ end
41
+
42
+ def process_locales_file(file)
43
+ current_checksum = calculate_checksum(file)
44
+ log_checksum(current_checksum)
45
+
46
+ first_load = @last_checksum.nil?
47
+ file_changed = current_checksum != @last_checksum
48
+ log_generate_status(first_load, file_changed)
49
+
50
+ return unless first_load || file_changed
51
+
52
+ @last_checksum = current_checksum
53
+ generate_translations(file)
54
+ end
55
+
56
+ def log_checksum(checksum)
57
+ puts "==> en.yml checksum: #{checksum}"
58
+ end
59
+
60
+ def log_generate_status(first_load, file_changed)
61
+ puts "==> en.yml generate: #{first_load || file_changed}"
62
+ end
63
+
64
+ def log_file_not_found
65
+ puts "en.yml file not found"
66
+ end
67
+
68
+ def configure_client
69
+ config = I18nAi.configuration.ai_settings
70
+ case config[:provider]
71
+ when "anthropic"
72
+ I18nAi::Clients::AnthropicClient.new
73
+ when "openai"
74
+ I18nAi::Clients::OpenAiClient.new
75
+ else
76
+ raise "Unknown AI provider: #{config[:provider]}"
77
+ end
78
+ end
79
+
80
+ def generate_translations(locales_file)
81
+ locales = load_locales(locales_file)
82
+ text_to_translate = locales.to_yaml
83
+ generate_locales = I18nAi.configuration.generate_locales
84
+
85
+ generate_locales.each do |locale|
86
+ response = translate_locales(locale, text_to_translate)
87
+ next unless response
88
+
89
+ translated_content = extract_translated_content(response)
90
+ save_translated_locales(locale, translated_content) if translated_content
91
+ end
92
+ end
93
+
94
+ def load_locales(locales_file)
95
+ YAML.load_file(locales_file)
96
+ end
97
+
98
+ def translate_locales(locale, text_to_translate)
99
+ @client.chat(locale, text_to_translate)
100
+ end
101
+
102
+ def extract_translated_content(response)
103
+ match_data = response.match(/```yaml(.*?)```/m)
104
+ match_data ? match_data[1].strip : nil
105
+ end
106
+
107
+ def save_translated_locales(locale, translated_content)
108
+ locales_file = Rails.root.join("config", "locales", "#{locale}.yml")
109
+ File.write(locales_file, translated_content)
110
+ end
111
+
112
+ def calculate_checksum(file_path)
113
+ Digest::SHA256.file(file_path).hexdigest
114
+ end
115
+ end
116
+
117
+ initializer "i18n_ai.configure_middleware", before: :build_middleware_stack do |app|
118
+ app.middleware.use I18nAiMiddleware
119
+ end
120
+ end
121
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module I18nAi
4
- VERSION = "0.1.1"
4
+ VERSION = "0.1.3"
5
5
  end
data/lib/i18n_ai.rb ADDED
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "i18n_ai/version"
4
+ require_relative "i18n_ai/railtie"
5
+ require_relative "i18n_ai/configuration"
6
+
7
+ # The I18nAi module provides functionality for integrating AI-based translation services
8
+ module I18nAi
9
+ class Error < StandardError; end
10
+
11
+ class << self
12
+ attr_writer :configuration
13
+
14
+ def configuration
15
+ @configuration ||= Configuration.new
16
+ end
17
+
18
+ def configure
19
+ yield(configuration)
20
+ end
21
+ end
22
+ end
metadata CHANGED
@@ -1,15 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: i18n-ai
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Estoque
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-08-05 00:00:00.000000000 Z
11
+ date: 2024-08-06 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: railties
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 6.0.0
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '8'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 6.0.0
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '8'
13
33
  - !ruby/object:Gem::Dependency
14
34
  name: anthropic
15
35
  requirement: !ruby/object:Gem::Requirement
@@ -52,13 +72,13 @@ files:
52
72
  - README.md
53
73
  - Rakefile
54
74
  - lib/i18n-ai.rb
55
- - lib/i18n-ai/clients/anthropic_client.rb
56
- - lib/i18n-ai/clients/base_client.rb
57
- - lib/i18n-ai/clients/open_ai_client.rb
58
- - lib/i18n-ai/configuration.rb
59
- - lib/i18n-ai/railtie.rb
60
- - lib/i18n-ai/version.rb
61
- - sig/i18n/ai.rbs
75
+ - lib/i18n_ai.rb
76
+ - lib/i18n_ai/clients/anthropic_client.rb
77
+ - lib/i18n_ai/clients/base_client.rb
78
+ - lib/i18n_ai/clients/open_ai_client.rb
79
+ - lib/i18n_ai/configuration.rb
80
+ - lib/i18n_ai/railtie.rb
81
+ - lib/i18n_ai/version.rb
62
82
  homepage: https://github.com/narralabs/i18n-ai
63
83
  licenses:
64
84
  - MIT
@@ -1,84 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "rails/railtie"
4
- require "digest"
5
-
6
- require_relative "clients/open_ai_client"
7
- require_relative "clients/anthropic_client"
8
-
9
- module I18nAi
10
- class Railtie < Rails::Railtie
11
- class I18nAiMiddleware
12
- def initialize(app)
13
- @app = app
14
- @client = configure_client
15
- @last_checksum = nil
16
- end
17
-
18
- def call(env)
19
- locales_file = Rails.root.join("config", "locales", "en.yml")
20
-
21
- if File.exist?(locales_file)
22
- current_checksum = calculate_checksum(locales_file)
23
- puts "==> en.yml checksum: #{current_checksum}"
24
- first_load = @last_checksum.nil?
25
- file_changed = current_checksum != @last_checksum
26
- puts "==> en.yml generate: #{first_load || file_changed}"
27
-
28
- if first_load || file_changed
29
- @last_checksum = current_checksum
30
- generate_translations(locales_file)
31
- end
32
- else
33
- puts "en.yml file not found"
34
- end
35
-
36
- @app.call(env)
37
- end
38
-
39
- private
40
-
41
- def configure_client
42
- config = I18nAi.configuration.ai_settings
43
- case config[:provider]
44
- when "anthropic"
45
- I18nAi::Clients::AnthropicClient.new
46
- when "openai"
47
- I18nAi::Clients::OpenAiClient.new
48
- else
49
- raise "Unknown AI provider: #{config[:provider]}"
50
- end
51
- end
52
-
53
- def generate_translations(locales_file)
54
- locales = YAML.load_file(locales_file)
55
- text_to_translate = locales.to_yaml
56
- generate_locales = I18nAi.configuration.generate_locales
57
-
58
- generate_locales.each do |locale|
59
- # Make a request to OpenAI to translate the locales to the specified locale
60
- response = @client.chat(
61
- locale, text_to_translate
62
- )
63
-
64
- next unless response
65
-
66
- match_data = response.match(/```yaml(.*?)```/m)
67
- str = match_data ? match_data[1].strip : nil
68
-
69
- # Save the response to <locale>.yml
70
- locales_file = Rails.root.join("config", "locales", "#{locale}.yml")
71
- File.write(locales_file, str)
72
- end
73
- end
74
-
75
- def calculate_checksum(file_path)
76
- Digest::SHA256.file(file_path).hexdigest
77
- end
78
- end
79
-
80
- initializer "i18n_ai.configure_middleware", before: :build_middleware_stack do |app|
81
- app.middleware.use I18nAiMiddleware
82
- end
83
- end
84
- end
data/sig/i18n/ai.rbs DELETED
@@ -1,6 +0,0 @@
1
- module I18n
2
- module Ai
3
- VERSION: String
4
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
5
- end
6
- end