immosquare-translate 0.1.12 → 0.1.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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 87dc92e836e2e404cccfa85c01fac2b8edf396aecc1a8a74558f66532942d6fd
|
4
|
+
data.tar.gz: 449976467c208d55e4dc7bf95c1089fae2889a954d64c385186789aabb1bd228
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c89194b90aa0b774308113059769a2d3021a13d7359df80baeab1539562acbd0dc1e8f5088f48d5bb7d66efcf5a4214cf49aa71cbfa609da6013dd080d8bf2be
|
7
|
+
data.tar.gz: 2eb2ee90027ebbbfe1fb38aee306c070b785de2aed44001290225d67f83b25ad872efd09d2910832e68bff65e91507b200ea9bfa865fd8cbbc67bc85a9514c89
|
@@ -5,11 +5,18 @@ module ImmosquareTranslate
|
|
5
5
|
SIMPLE_QUOTE = "'".freeze
|
6
6
|
DOUBLE_QUOTE = '"'.freeze
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
##============================================================##
|
9
|
+
## https://platform.openai.com/docs/pricing
|
10
|
+
## List updated on : 21/05/2025
|
11
|
+
##============================================================##
|
12
|
+
OPEN_AI_MODELS = [
|
13
|
+
{:nickname => "gpt-3.5", :name => "gpt-3.5-turbo-0125", :default => false, :window_tokens => 16_385, :output_tokens => 4_096, :input_price_for_1m => 0.50, :output_price_for_1m => 1.50, :group_size => 75},
|
14
|
+
{:nickname => "gpt-4", :name => "gpt-4-turbo-2024-04-09", :default => false, :window_tokens => 128_000, :output_tokens => 4_096, :input_price_for_1m => 10.00, :output_price_for_1m => 30.00, :group_size => 75},
|
15
|
+
{:nickname => "gpt-4o-mini", :name => "gpt-4o-mini", :default => false, :window_tokens => 128_000, :output_tokens => 16_384, :input_price_for_1m => 0.15, :output_price_for_1m => 0.60, :group_size => 75},
|
16
|
+
{:nickname => "gpt-4o", :name => "gpt-4o-2024-08-06", :default => false, :window_tokens => 128_000, :output_tokens => 16_384, :input_price_for_1m => 2.50, :output_price_for_1m => 10.00, :group_size => 75},
|
17
|
+
{:nickname => "gpt-4.1-nano", :name => "gpt-4.1-nano", :default => false, :window_tokens => 1_000_000, :output_tokens => 32_768, :input_price_for_1m => 0.10, :output_price_for_1m => 0.40, :group_size => 75},
|
18
|
+
{:nickname => "gpt-4.1-mini", :name => "gpt-4.1-mini", :default => false, :window_tokens => 1_000_000, :output_tokens => 32_768, :input_price_for_1m => 0.40, :output_price_for_1m => 1.60, :group_size => 75},
|
19
|
+
{:nickname => "gpt-4.1", :name => "gpt-4.1-2025-04-14", :default => true, :window_tokens => 1_000_000, :output_tokens => 32_768, :input_price_for_1m => 2.00, :output_price_for_1m => 8.00, :group_size => 75}
|
13
20
|
].freeze
|
14
21
|
end
|
15
22
|
end
|
@@ -1,3 +1,7 @@
|
|
1
|
+
require "immosquare-constants"
|
2
|
+
require "iso-639"
|
3
|
+
require "countries"
|
4
|
+
|
1
5
|
module ImmosquareTranslate
|
2
6
|
module Translator
|
3
7
|
extend SharedMethods
|
@@ -10,49 +14,78 @@ module ImmosquareTranslate
|
|
10
14
|
## from : string
|
11
15
|
## to : array
|
12
16
|
##============================================================##
|
13
|
-
def translate(
|
17
|
+
def translate(texts, from, to)
|
14
18
|
begin
|
15
19
|
raise("Error: openai_api_key not found in config_dev.yml") if ImmosquareTranslate.configuration.openai_api_key.nil?
|
16
20
|
raise("Error: locale from is not a locale") if !from.is_a?(String) || from.size != 2
|
17
|
-
raise("Error: locales is not an array of locales") if !to.is_a?(Array) || to.empty? || to.any? {|l| !l.is_a?(String)
|
21
|
+
raise("Error: locales is not an array of locales") if !to.is_a?(Array) || to.empty? || to.any? {|l| !l.is_a?(String) }
|
22
|
+
|
23
|
+
model_name = ImmosquareTranslate.configuration.openai_model
|
24
|
+
model = OPEN_AI_MODELS.find {|m| m[:name] == model_name || m[:nickname] == model_name }
|
25
|
+
model = OPEN_AI_MODELS.find {|m| m[:default] == true } if model.nil?
|
26
|
+
|
27
|
+
puts("To translate, we will use the model: #{model[:nickname]}")
|
18
28
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
to_iso
|
29
|
+
##============================================================##
|
30
|
+
## We get the language name and the country name for each locale
|
31
|
+
##============================================================##
|
32
|
+
from_language_name = ISO_639.find_by_code(from).english_name.split(";").first
|
33
|
+
to_iso = to
|
34
|
+
.reject {|code| ImmosquareConstants::Locale.native_name_for_locale(code).nil? }
|
35
|
+
.map do |iso|
|
36
|
+
iso_parts = iso.split("-")
|
37
|
+
iso_language = iso_parts.first.downcase
|
38
|
+
iso_country = iso_parts.size > 1 ? iso_parts.last.downcase : nil
|
39
|
+
language_english_name = ISO_639.find_by_code(iso_language)&.english_name&.split(";")&.first
|
40
|
+
country_english_name = iso_country.nil? ? nil : ISO3166::Country.find_country_by_alpha2(iso_country)&.iso_short_name
|
41
|
+
[iso, language_english_name, country_english_name]
|
42
|
+
end
|
43
|
+
|
44
|
+
##============================================================##
|
45
|
+
## Request headers
|
46
|
+
##============================================================##
|
24
47
|
headers = {
|
25
48
|
"Content-Type" => "application/json",
|
26
49
|
"Authorization" => "Bearer #{ImmosquareTranslate.configuration.openai_api_key}"
|
27
50
|
}
|
28
51
|
|
52
|
+
##============================================================##
|
53
|
+
## System prompt
|
54
|
+
##============================================================##
|
29
55
|
prompt_system = "As a sophisticated translation AI, your role is to translate sentences from a specified source language to multiple target languages.\n" \
|
56
|
+
"We pass you target languages as an array of arrays with this format: [iso_code to use (2 or 4 letters), language target name, country name (country vocabulary to use, this parameter is optional, can be null)].\n" \
|
30
57
|
"Rules to respect:\n" \
|
31
|
-
"- Use
|
32
|
-
"- Respond with an array of
|
33
|
-
"- Format the translation output as a JSON string adhering to the following structure: {\"datas\":[{\"locale_iso\": \"Translated Text\"}]} where locale_iso is the
|
58
|
+
"- Use the inputted ISO codes for specifying languages.\n" \
|
59
|
+
"- Respond with an array of flat objects in JSON (minified, without any extraneous characters or formatting).\n" \
|
60
|
+
"- Format the translation output as a JSON string adhering to the following structure: {\"datas\":[{\"locale_iso\": \"Translated Text\"}]} where locale_iso is the language code specifying the language and regional variant.\n" \
|
34
61
|
"- Ensure that the output does not include markdown (```json) or any other formatting characters. Adhere to the JSON structure meticulously.\n" \
|
35
62
|
"- Correct any spelling or grammatical errors in the source text before translating.\n" \
|
36
|
-
"- If the source language is also a target language, include the corrected version of the sentence for that language
|
63
|
+
"- If the source language is also a target language, include the corrected version of the sentence for that language.\n" \
|
37
64
|
"- If string to translate is html, you should return the translated html.\n" \
|
38
|
-
"- If string to translate contains underscores in row, keep them, don't remove them
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
65
|
+
"- If string to translate contains underscores in a row, keep them, don't remove them.\n" \
|
66
|
+
"- For regional variants (e.g., fr-CA or en-US), ensure the translation reflects the cultural and linguistic norms specific to that country. This includes word choices, idiomatic expressions, and spellings commonly used in that region.\n" \
|
67
|
+
"- Example: For the text 'I am going to the supermarket', the translation for 'fr-CA' should be 'Je vais à l'épicerie', as 'épicerie' is more common in Canadian French than 'supermarché'.\n" \
|
68
|
+
"- Ensure that translations for each input string are grouped together in a single JSON object. Each object must include all requested translations for that string, using the iso_code as keys.\n" \
|
69
|
+
"- For multiple input strings, return an array of objects, where each object corresponds to an input string and contains all its translations.\n" \
|
70
|
+
"- Example output for two input strings 'Hello' and 'Goodbye' with target languages ['en', 'es', 'fr']: [{\"en\":\"Hello\",\"es\":\"Hola\",\"fr\":\"Bonjour\"},{\"en\":\"Goodbye\",\"es\":\"Adiós\",\"fr\":\"Au revoir\"}].\n"
|
43
71
|
|
72
|
+
##============================================================##
|
73
|
+
## User prompt
|
74
|
+
##============================================================##
|
75
|
+
prompt = "Translate the #{texts.size} following #{texts.size == 1 ? "text" : "texts"} from the source language: #{from_language_name} to the target languages specified: #{to_iso}."
|
44
76
|
|
45
77
|
##============================================================##
|
46
78
|
## we replace the \n \t by ___ to avoid JSON parsing errors
|
47
79
|
## We use the same symbol to replace the \n and \t because
|
48
80
|
## if we use different symbols sometimes the API inverse them.
|
49
81
|
##============================================================##
|
50
|
-
|
82
|
+
texts.each_with_index do |sentence, index|
|
51
83
|
prompt += "\n#{index + 1}: #{sentence.gsub("\n", "___").gsub("\t", "____")}"
|
52
84
|
end
|
53
85
|
|
54
|
-
|
55
|
-
|
86
|
+
##============================================================##
|
87
|
+
## Request body
|
88
|
+
##============================================================##
|
56
89
|
body = {
|
57
90
|
:model => model[:name],
|
58
91
|
:messages => [
|
@@ -64,10 +97,11 @@ module ImmosquareTranslate
|
|
64
97
|
|
65
98
|
|
66
99
|
t0 = Time.now
|
67
|
-
|
100
|
+
url = "https://api.openai.com/v1/chat/completions"
|
101
|
+
call = HTTParty.post(url, :body => body.to_json, :headers => headers, :timeout => 500)
|
68
102
|
|
69
103
|
|
70
|
-
puts("
|
104
|
+
puts("OpenAI api response in #{(Time.now - t0).round(2)} seconds")
|
71
105
|
raise(call["error"]["message"]) if call.code != 200
|
72
106
|
|
73
107
|
##============================================================##
|
@@ -77,6 +111,7 @@ module ImmosquareTranslate
|
|
77
111
|
choice = response["choices"][0]
|
78
112
|
raise("Result is not complete") if choice["finish_reason"] != "stop"
|
79
113
|
|
114
|
+
|
80
115
|
##============================================================##
|
81
116
|
## We calculate the estimate price of the call
|
82
117
|
##============================================================##
|
@@ -85,17 +120,18 @@ module ImmosquareTranslate
|
|
85
120
|
price = input_price + output_price
|
86
121
|
puts("Estimate price => #{input_price.round(3)} + #{output_price.round(3)} = #{price.round(3)} USD")
|
87
122
|
|
88
|
-
|
89
123
|
##============================================================##
|
90
124
|
## On s'assure de ne renvoyer que les locales demandées
|
91
125
|
## car l'API peut renvoyer des locales non demandées...
|
92
126
|
##============================================================##
|
93
|
-
|
94
|
-
datas = content["datas"]
|
127
|
+
datas = JSON.parse(choice["message"]["content"])
|
95
128
|
datas.map do |hash|
|
96
129
|
hash
|
97
|
-
.select {|key, _| to.include?(key) }
|
130
|
+
.select {|key, _| to.map(&:downcase).include?(key.downcase) }
|
98
131
|
.transform_values {|value| value.gsub("____", "\t").gsub("___", "\n") }
|
132
|
+
.transform_keys do |key|
|
133
|
+
key.to_s.split("-").map.with_index {|part, index| index == 0 ? part.downcase : part.upcase }.join("-").to_sym
|
134
|
+
end
|
99
135
|
end.reject(&:empty?)
|
100
136
|
rescue StandardError => e
|
101
137
|
puts(e.message)
|
@@ -10,18 +10,18 @@ module ImmosquareTranslate
|
|
10
10
|
|
11
11
|
def translate(file_path, locale_to, options = {})
|
12
12
|
begin
|
13
|
-
|
13
|
+
##============================================================##
|
14
14
|
## options
|
15
|
-
|
15
|
+
##============================================================##
|
16
16
|
options = {
|
17
17
|
:reset_translations => false
|
18
18
|
}.merge(options)
|
19
19
|
options[:reset_translations] = false if ![true, false].include?(options[:reset_translations])
|
20
20
|
|
21
21
|
|
22
|
-
|
22
|
+
##============================================================##
|
23
23
|
## Load config keys from config_dev.yml
|
24
|
-
|
24
|
+
##============================================================##
|
25
25
|
raise("Error: openai_api_key not found in config_dev.yml") if ImmosquareTranslate.configuration.openai_api_key.nil?
|
26
26
|
raise("Error: File #{file_path} not found") if !File.exist?(file_path)
|
27
27
|
raise("Error: locale is not a locale") if !locale_to.is_a?(String) || locale_to.size != 2
|
@@ -124,7 +124,8 @@ module ImmosquareTranslate
|
|
124
124
|
## format = "string" and keys_only = true => ["fr.demo1", "fr.demo2.demo2-1"]
|
125
125
|
## format = "array" and keys_only = false => [[["fr", "demo1"], "demo1"], [["fr", "demo2", "demo2-1"], "demo2-1"]]
|
126
126
|
## format = "array" and keys_only = true => [["fr", "demo1"], ["fr", "demo2", "demo2-1"]]
|
127
|
-
##
|
127
|
+
## ---------
|
128
|
+
##============================================================##
|
128
129
|
def translatable_array(hash, key = nil, result = [], **options)
|
129
130
|
options = {
|
130
131
|
:format => "string",
|
@@ -162,12 +163,8 @@ module ImmosquareTranslate
|
|
162
163
|
|
163
164
|
##============================================================##
|
164
165
|
## Translate with OpenAI
|
165
|
-
##
|
166
|
-
## [
|
167
|
-
## ["en.mlsconnect.contact_us", "Nous contacter", "Contact us"],
|
168
|
-
## ["en.mlsconnect.description", "Description", nil],
|
169
|
-
## ...
|
170
|
-
## ]
|
166
|
+
## [["en.mlsconnect.contact_us", "Nous contacter", "Contact us"],
|
167
|
+
## ["en.mlsconnect.description", "Description", nil]]
|
171
168
|
##============================================================##
|
172
169
|
def translate_with_open_ai(array, from, to)
|
173
170
|
##============================================================##
|
@@ -175,8 +172,8 @@ module ImmosquareTranslate
|
|
175
172
|
## https://openai.com/pricing
|
176
173
|
##============================================================##
|
177
174
|
model_name = ImmosquareTranslate.configuration.openai_model
|
178
|
-
model = OPEN_AI_MODELS.find {|m| m[:name] == model_name }
|
179
|
-
model = OPEN_AI_MODELS.find {|m| m[:
|
175
|
+
model = OPEN_AI_MODELS.find {|m| m[:name] == model_name || m[:nickname] == model_name }
|
176
|
+
model = OPEN_AI_MODELS.find {|m| m[:default] == true } if model.nil?
|
180
177
|
|
181
178
|
##============================================================##
|
182
179
|
## Manage blank values
|
@@ -192,7 +189,7 @@ module ImmosquareTranslate
|
|
192
189
|
## we want to send as little data as possible to openAI because
|
193
190
|
## we pay for the volume of data sent. So we're going to send. We put
|
194
191
|
## a number rather than a string for the translations to be made.
|
195
|
-
##
|
192
|
+
## ---------
|
196
193
|
## Remove the translations that have already been made
|
197
194
|
##============================================================##
|
198
195
|
data_open_ai = array.clone
|
@@ -247,7 +244,7 @@ module ImmosquareTranslate
|
|
247
244
|
## https://platform.openai.com/tokenizer
|
248
245
|
## English: 75 words => 100 tokens
|
249
246
|
## French : 55 words => 100 tokens
|
250
|
-
##
|
247
|
+
## ---------
|
251
248
|
## For each array value we add 5 tokens for the array format.
|
252
249
|
## [1, "my_word"],
|
253
250
|
## [ => first token
|
@@ -255,8 +252,8 @@ module ImmosquareTranslate
|
|
255
252
|
## , => third token
|
256
253
|
## " => fourth token
|
257
254
|
## ]" => fifth token
|
258
|
-
##
|
259
|
-
|
255
|
+
## ---------
|
256
|
+
## data_open_ai.inspect.size => to get the total number of characters in the array
|
260
257
|
## with the array structure [""],
|
261
258
|
##============================================================##
|
262
259
|
estimation_for_100_tokens = from == "fr" ? 55 : 75
|
@@ -269,7 +266,7 @@ module ImmosquareTranslate
|
|
269
266
|
##============================================================##
|
270
267
|
## Now each slice of the array should no be more than window_tokens
|
271
268
|
## of the model.... We can now translate each slice.
|
272
|
-
##
|
269
|
+
## ---------
|
273
270
|
## Normally we could send the whole slice at once and tell the api to continue if its response is not tarnished...
|
274
271
|
## But it should manage if a word is cut etc...
|
275
272
|
## For the moment we cut it into small group for which we are sure not to exceed the limit
|
@@ -291,7 +288,8 @@ module ImmosquareTranslate
|
|
291
288
|
:temperature => 0.0
|
292
289
|
}
|
293
290
|
t0 = Time.now
|
294
|
-
|
291
|
+
url = "https://api.openai.com/v1/chat/completions"
|
292
|
+
call = HTTParty.post(url, :body => body.to_json, :headers => headers, :timeout => 500)
|
295
293
|
|
296
294
|
puts("responded in #{(Time.now - t0).round(2)} seconds")
|
297
295
|
raise(call["error"]["message"]) if call.code != 200
|
data/lib/immosquare-translate.rb
CHANGED
@@ -5,15 +5,12 @@ require_relative "immosquare-translate/translator"
|
|
5
5
|
require_relative "immosquare-translate/railtie" if defined?(Rails)
|
6
6
|
|
7
7
|
|
8
|
-
##===========================================================================##
|
9
|
-
##
|
10
|
-
##===========================================================================##
|
11
8
|
module ImmosquareTranslate
|
12
9
|
class << self
|
13
10
|
|
14
|
-
|
11
|
+
##============================================================##
|
15
12
|
## Gem configuration
|
16
|
-
|
13
|
+
##============================================================##
|
17
14
|
attr_writer :configuration
|
18
15
|
|
19
16
|
def configuration
|
@@ -25,6 +22,5 @@ module ImmosquareTranslate
|
|
25
22
|
end
|
26
23
|
|
27
24
|
|
28
|
-
|
29
25
|
end
|
30
26
|
end
|
metadata
CHANGED
@@ -1,63 +1,114 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: immosquare-translate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- immosquare
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: httparty
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
16
15
|
requirements:
|
17
|
-
- - "
|
16
|
+
- - ">"
|
18
17
|
- !ruby/object:Gem::Version
|
19
18
|
version: '0'
|
19
|
+
- - "<="
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '100'
|
20
22
|
type: :runtime
|
21
23
|
prerelease: false
|
22
24
|
version_requirements: !ruby/object:Gem::Requirement
|
23
25
|
requirements:
|
24
|
-
- - "
|
26
|
+
- - ">"
|
25
27
|
- !ruby/object:Gem::Version
|
26
28
|
version: '0'
|
29
|
+
- - "<="
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: '100'
|
27
32
|
- !ruby/object:Gem::Dependency
|
28
33
|
name: immosquare-yaml
|
29
34
|
requirement: !ruby/object:Gem::Requirement
|
30
35
|
requirements:
|
31
|
-
- - "
|
36
|
+
- - ">"
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
- - "<="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '100'
|
42
|
+
type: :runtime
|
43
|
+
prerelease: false
|
44
|
+
version_requirements: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
- - "<="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '100'
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
name: immosquare-constants
|
54
|
+
requirement: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">"
|
32
57
|
- !ruby/object:Gem::Version
|
33
58
|
version: '0'
|
34
|
-
- - "
|
59
|
+
- - "<="
|
35
60
|
- !ruby/object:Gem::Version
|
36
|
-
version:
|
61
|
+
version: '100'
|
37
62
|
type: :runtime
|
38
63
|
prerelease: false
|
39
64
|
version_requirements: !ruby/object:Gem::Requirement
|
40
65
|
requirements:
|
41
|
-
- - "
|
66
|
+
- - ">"
|
42
67
|
- !ruby/object:Gem::Version
|
43
68
|
version: '0'
|
44
|
-
- - "
|
69
|
+
- - "<="
|
45
70
|
- !ruby/object:Gem::Version
|
46
|
-
version:
|
71
|
+
version: '100'
|
47
72
|
- !ruby/object:Gem::Dependency
|
48
73
|
name: iso-639
|
49
74
|
requirement: !ruby/object:Gem::Requirement
|
50
75
|
requirements:
|
51
|
-
- - "
|
76
|
+
- - ">"
|
52
77
|
- !ruby/object:Gem::Version
|
53
78
|
version: '0'
|
79
|
+
- - "<="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '100'
|
54
82
|
type: :runtime
|
55
83
|
prerelease: false
|
56
84
|
version_requirements: !ruby/object:Gem::Requirement
|
57
85
|
requirements:
|
58
|
-
- - "
|
86
|
+
- - ">"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
- - "<="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '100'
|
92
|
+
- !ruby/object:Gem::Dependency
|
93
|
+
name: countries
|
94
|
+
requirement: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">"
|
59
97
|
- !ruby/object:Gem::Version
|
60
98
|
version: '0'
|
99
|
+
- - "<="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '100'
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">"
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
- - "<="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '100'
|
61
112
|
description: ImmosquareTranslate brings the power of OpenAI to Ruby applications,
|
62
113
|
offering the ability to translate not just YAML files, but also arrays, web pages,
|
63
114
|
and other data structures. Tailored for developers in multilingual settings, it
|
@@ -81,7 +132,6 @@ homepage: https://github.com/immosquare/immosquare-translate
|
|
81
132
|
licenses:
|
82
133
|
- MIT
|
83
134
|
metadata: {}
|
84
|
-
post_install_message:
|
85
135
|
rdoc_options: []
|
86
136
|
require_paths:
|
87
137
|
- lib
|
@@ -89,15 +139,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
89
139
|
requirements:
|
90
140
|
- - ">="
|
91
141
|
- !ruby/object:Gem::Version
|
92
|
-
version: 2.
|
142
|
+
version: 3.2.6
|
93
143
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
144
|
requirements:
|
95
145
|
- - ">="
|
96
146
|
- !ruby/object:Gem::Version
|
97
147
|
version: '0'
|
98
148
|
requirements: []
|
99
|
-
rubygems_version: 3.
|
100
|
-
signing_key:
|
149
|
+
rubygems_version: 3.6.9
|
101
150
|
specification_version: 4
|
102
151
|
summary: AI-powered translations for Ruby applications, supporting a wide range of
|
103
152
|
formats.
|