better_translate 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ac3bc8d98853820f1c6367bbbe4fb36733a872de35eef7ff8bc47349fc9376e5
4
+ data.tar.gz: fa486ddb0bf587faee2792bbca54982ddbdffcc44b4b183e9c0de1c849f917b7
5
+ SHA512:
6
+ metadata.gz: 643e1688cc0171ddee6bfeb848aa1d555922bf2c44907afc56981ea0b5c9dd9ce8fa5788b509596eb53735cd4ce63e1adbccaeb1592f5cb3d1653da794a0c415
7
+ data.tar.gz: ea2451b736c946d2bead72f3bf36dab06fb38e2037662c160a400f73a1854919314bfecb0a5081b63add8b7a66b1402ae85b3cfa42af10149cb9faf9677fba90
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 alessiobussolari
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,116 @@
1
+ # BetterTranslate
2
+
3
+ BetterTranslate is a Ruby gem that enables you to translate YAML files from a source language into one or more target languages using translation providers such as ChatGPT (OpenAI) and Google Gemini. The gem supports two translation modes:
4
+
5
+ - **Override**: Completely rewrites the translated file.
6
+ - **Incremental**: Updates the translated file only with new or modified keys while keeping existing ones.
7
+
8
+ Configuration is centralized via an initializer (for example, in a Rails app), where you can set API keys, the source language, target languages, key exclusions, the output folder, and the translation mode. Additionally, BetterTranslate integrates progress tracking using the [ruby-progressbar](https://github.com/jfelchner/ruby-progressbar) gem.
9
+
10
+ ## Features
11
+
12
+ - **Multi-language YAML Translation**: Translates YAML files from a source language into one or more target languages.
13
+ - **Multiple Providers**: Supports ChatGPT (OpenAI) and Google Gemini (with potential for extending to other providers in the future).
14
+ - **Translation Modes**:
15
+ - **Override**: Rewrites the file from scratch.
16
+ - **Incremental**: Updates only missing or modified keys.
17
+ - **Centralized Configuration**: Configured via an initializer with settings for API keys, source language, target languages, exclusions (using dot notation), and the output folder.
18
+ - **Progress Bar**: Displays the translation progress using ruby-progressbar.
19
+
20
+ ## Installation
21
+
22
+ Add the gem to your Gemfile:
23
+
24
+ ```ruby
25
+ gem 'better_translate'
26
+
27
+ Then run:
28
+
29
+ ```bash
30
+ bundle install
31
+ ```
32
+
33
+ Or install the gem manually:
34
+
35
+ ```bash
36
+ gem install better_translate
37
+ ```
38
+
39
+ ## Configuration
40
+
41
+ In a Rails application, generate the initializer by running:
42
+
43
+ ```bash
44
+ rails generate better_translate:install
45
+ ```
46
+
47
+ This command creates the file `config/initializers/better_translate.rb` with a default configuration. An example configuration is:
48
+
49
+ ```ruby
50
+ BetterTranslate.configure do |config|
51
+ # Choose the provider to use: :chatgpt or :gemini
52
+ config.provider = :chatgpt
53
+
54
+ # API key for ChatGPT (OpenAI)
55
+ config.openai_key = ENV.fetch("OPENAI_API_KEY") { "YOUR_OPENAI_API_KEY" }
56
+
57
+ # API key for Google Gemini
58
+ config.google_gemini_key = ENV.fetch("GOOGLE_GEMINI_KEY") { "YOUR_GOOGLE_GEMINI_KEY" }
59
+
60
+ # Source language (e.g., "en" if the source file is in English)
61
+ config.source_language = "en"
62
+
63
+ # Output folder where the translated files will be saved
64
+ config.output_folder = Rails.root.join("config", "locales", "translated").to_s
65
+
66
+ # List of target languages (short_name and name)
67
+ config.target_languages = [
68
+ # Example:
69
+ { short_name: "it", name: "italian" }
70
+ ]
71
+
72
+ # Global exclusions (keys in dot notation) to exclude from translation
73
+ config.global_exclusions = [
74
+ "key.child_key",
75
+ ]
76
+
77
+ # Language-specific exclusions (optional)
78
+ config.exclusions_per_language = {
79
+ "ru" => []
80
+ }
81
+
82
+ # Path to the input file (e.g., en.yml)
83
+ config.input_file = Rails.root.join("config", "locales", "en.yml").to_s
84
+
85
+ # Translation mode: :override or :incremental
86
+ config.translation_method = :override
87
+ end
88
+ ```
89
+
90
+ ## Usage
91
+
92
+ ### YAML File Translation
93
+
94
+ To start the translation process, simply call the `magic` method:
95
+
96
+ ```ruby
97
+ BetterTranslate.magic
98
+ ```
99
+
100
+ This will execute the process that:
101
+ 1. Reads the input YAML file.
102
+ 2. Applies any filters (exclusions).
103
+ 3. Translates the strings from the source language to the configured target languages.
104
+ 4. Writes the translated files to the output folder, either in **override** or **incremental** mode based on the configuration.
105
+
106
+ ## Contributing
107
+
108
+ Pull requests are welcome! If you would like to suggest improvements or new features, please open an issue to discuss your ideas before submitting a pull request.
109
+
110
+ ## Changelog
111
+
112
+ See the [CHANGELOG](https://github.com/alessiobussolari/better_translate/blob/main/CHANGELOG.md) for a summary of changes.
113
+
114
+ ## License
115
+
116
+ BetterTranslate is distributed under the MIT license. See the [LICENSE](LICENSE) file for more details.
@@ -0,0 +1,18 @@
1
+ module BetterTranslate
2
+ module Providers
3
+ class BaseProvider
4
+ def initialize(api_key)
5
+ @api_key = api_key
6
+ end
7
+
8
+ # Metodo da implementare nelle classi derivate.
9
+ # @param text [String] testo da tradurre.
10
+ # @param target_lang_code [String] codice della lingua di destinazione (es. "en").
11
+ # @param target_lang_name [String] nome della lingua di destinazione (es. "English").
12
+ # @return [String] testo tradotto.
13
+ def translate(text, target_lang_code, target_lang_name)
14
+ raise NotImplementedError, "Il provider #{self.class} deve implementare il metodo translate"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,38 @@
1
+ module BetterTranslate
2
+ module Providers
3
+ class ChatgptProvider < BaseProvider
4
+ # Utilizza l'API di OpenAI per tradurre il testo.
5
+ def translate(text, target_lang_code, target_lang_name)
6
+ uri = URI("https://api.openai.com/v1/chat/completions")
7
+ headers = {
8
+ "Content-Type" => "application/json",
9
+ "Authorization" => "Bearer #{@api_key}"
10
+ }
11
+
12
+ # Costruiamo il prompt per tradurre il testo.
13
+ body = {
14
+ model: "gpt-3.5-turbo",
15
+ messages: [
16
+ { role: "system", content: "Sei un traduttore professionale. Traduci esattamente il seguente testo da #{BetterTranslate.configuration.source_language} a #{target_lang_name} senza aggiungere commenti, spiegazioni o alternative. Fornisci solamente la traduzione diretta:" },
17
+ { role: "user", content: "#{text}" }
18
+ ],
19
+ temperature: 0.3
20
+ }
21
+
22
+ http = Net::HTTP.new(uri.host, uri.port)
23
+ http.use_ssl = true
24
+ request = Net::HTTP::Post.new(uri.path, headers)
25
+ request.body = body.to_json
26
+
27
+ response = http.request(request)
28
+ if response.is_a?(Net::HTTPSuccess)
29
+ json = JSON.parse(response.body)
30
+ translated_text = json.dig("choices", 0, "message", "content")
31
+ translated_text ? translated_text.strip : text
32
+ else
33
+ raise "Errore durante la traduzione con ChatGPT: #{response.body}"
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,35 @@
1
+ module BetterTranslate
2
+ module Providers
3
+ class GeminiProvider < BaseProvider
4
+ # Esempio di implementazione per Google Gemini.
5
+ # Nota: L'endpoint e i parametri sono ipotetici e vanno sostituiti con quelli reali secondo la documentazione ufficiale.
6
+ def translate(text, target_lang_code, target_lang_name)
7
+ uri = URI("https://gemini.googleapis.com/v1/translate")
8
+ headers = {
9
+ "Content-Type" => "application/json",
10
+ "Authorization" => "Bearer #{@api_key}"
11
+ }
12
+
13
+ body = {
14
+ input_text: text,
15
+ target_language: target_lang_code,
16
+ model: "gemini" # oppure altri parametri richiesti dall'API
17
+ }
18
+
19
+ http = Net::HTTP.new(uri.host, uri.port)
20
+ http.use_ssl = true
21
+ request = Net::HTTP::Post.new(uri.path, headers)
22
+ request.body = body.to_json
23
+
24
+ response = http.request(request)
25
+ if response.is_a?(Net::HTTPSuccess)
26
+ json = JSON.parse(response.body)
27
+ translated_text = json["translatedText"]
28
+ translated_text ? translated_text.strip : text
29
+ else
30
+ raise "Errore durante la traduzione con Gemini: #{response.body}"
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,25 @@
1
+ module BetterTranslate
2
+ class Service
3
+ def initialize
4
+ @provider_name = BetterTranslate.configuration.provider
5
+ end
6
+
7
+ # Metodo per tradurre un testo utilizzando il provider selezionato.
8
+ def translate(text, target_lang_code, target_lang_name)
9
+ provider_instance.translate(text, target_lang_code, target_lang_name)
10
+ end
11
+
12
+ private
13
+
14
+ def provider_instance
15
+ @provider_instance ||= case @provider_name
16
+ when :chatgpt
17
+ Providers::ChatgptProvider.new(BetterTranslate.configuration.openai_key)
18
+ when :gemini
19
+ Providers::GeminiProvider.new(BetterTranslate.configuration.google_gemini_key)
20
+ else
21
+ raise "Provider non supportato: #{@provider_name}"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,131 @@
1
+ module BetterTranslate
2
+ class Translator
3
+ class << self
4
+ def work
5
+ puts "Avvio della traduzione dei file..."
6
+
7
+ translations = read_yml_source
8
+
9
+ # Rimuove le chiavi da escludere (global_exclusions) dalla struttura letta
10
+ filtered_translations = remove_exclusions(
11
+ translations, BetterTranslate.configuration.global_exclusions
12
+ )
13
+
14
+ BetterTranslate.configuration.target_languages.each do |target_lang|
15
+ puts "Inizio traduzione da #{BetterTranslate.configuration.source_language} a #{target_lang[:short_name]}"
16
+ service = BetterTranslate::Service.new
17
+ translated_data = translate_with_progress(filtered_translations, service, target_lang[:short_name], target_lang[:name])
18
+ BetterTranslate::Writer.write_translations(translated_data, target_lang[:short_name])
19
+ puts "Traduzione completata da #{BetterTranslate.configuration.source_language} a #{target_lang[:short_name]}"
20
+ end
21
+
22
+ "Traduzione iniziata! #{filtered_translations.inspect}"
23
+ end
24
+
25
+ private
26
+
27
+ # Legge il file YAML in base al percorso fornito.
28
+ #
29
+ # @param file_path [String] percorso del file YAML da leggere
30
+ # @return [Hash] struttura dati contenente le traduzioni
31
+ # @raise [StandardError] se il file non esiste
32
+ def read_yml_source
33
+ file_path = BetterTranslate.configuration.input_file
34
+ unless File.exist?(file_path)
35
+ raise "File non trovato: #{file_path}"
36
+ end
37
+
38
+ YAML.load_file(file_path)
39
+ end
40
+
41
+ # Rimuove le chiavi specificate in exclusion_list dalla struttura dati,
42
+ # calcolando i percorsi a partire dal contenuto della lingua di partenza.
43
+ #
44
+ # Ad esempio, se il file YAML è:
45
+ # { "en" => { "sample" => { "valid" => "valid", "excluded" => "Excluded" } } }
46
+ # e exclusion_list = ["sample.excluded"],
47
+ # il risultato sarà:
48
+ # { "en" => { "sample" => { "valid" => "valid" } } }
49
+ #
50
+ # @param data [Hash, Array, Object] La struttura dati da filtrare.
51
+ # @param exclusion_list [Array<String>] Lista dei percorsi (in dot notation) da escludere.
52
+ # @param current_path [Array] Il percorso corrente (usato in maniera ricorsiva).
53
+ # @return [Hash, Array, Object] La struttura dati filtrata.
54
+ def remove_exclusions(data, exclusion_list, current_path = [])
55
+ if data.is_a?(Hash)
56
+ data.each_with_object({}) do |(key, value), result|
57
+ # Se siamo al livello top-level e la chiave corrisponde alla lingua di partenza,
58
+ # resettare il percorso (così da escludere "en" dal percorso finale)
59
+ new_path = if current_path.empty? && key == BetterTranslate.configuration.source_language
60
+ []
61
+ else
62
+ current_path + [key]
63
+ end
64
+
65
+ path_string = new_path.join(".")
66
+ unless exclusion_list.include?(path_string)
67
+ result[key] = remove_exclusions(value, exclusion_list, new_path)
68
+ end
69
+ end
70
+ elsif data.is_a?(Array)
71
+ data.map.with_index do |item, index|
72
+ remove_exclusions(item, exclusion_list, current_path + [index])
73
+ end
74
+ else
75
+ data
76
+ end
77
+ end
78
+
79
+ # Metodo ricorsivo che percorre la struttura, traducendo ogni stringa e aggiornando il progresso.
80
+ #
81
+ # @param data [Hash, Array, String] La struttura dati da tradurre.
82
+ # @param provider [Object] Il provider che risponde al metodo translate.
83
+ # @param target_lang_code [String] Codice della lingua target (es. "en").
84
+ # @param target_lang_name [String] Nome della lingua target (es. "English").
85
+ # @param progress [Hash] Un hash con le chiavi :count e :total per monitorare il progresso.
86
+ # @return [Hash, Array, String] La struttura tradotta.
87
+ def deep_translate_with_progress(data, service, target_lang_code, target_lang_name, progress)
88
+ if data.is_a?(Hash)
89
+ data.each_with_object({}) do |(key, value), result|
90
+ result[key] = deep_translate_with_progress(value, service, target_lang_code, target_lang_name, progress)
91
+ end
92
+ elsif data.is_a?(Array)
93
+ data.map do |item|
94
+ deep_translate_with_progress(item, service, target_lang_code, target_lang_name, progress)
95
+ end
96
+ elsif data.is_a?(String)
97
+ progress.increment
98
+ service.translate(data, target_lang_code, target_lang_name)
99
+ else
100
+ data
101
+ end
102
+ end
103
+
104
+ # Metodo principale per tradurre l'intera struttura dati, con monitoraggio del progresso.
105
+ #
106
+ # @param data [Hash, Array, String] la struttura dati da tradurre
107
+ # @param provider [Object] il provider da usare per tradurre (deve implementare translate)
108
+ # @param target_lang_code [String] codice della lingua target
109
+ # @param target_lang_name [String] nome della lingua target
110
+ # @return la struttura tradotta
111
+ def translate_with_progress(data, service, target_lang_code, target_lang_name)
112
+ total = count_strings(data)
113
+ progress = ProgressBar.create(total: total, format: '%a %B %p%% %t')
114
+ deep_translate_with_progress(data, service, target_lang_code, target_lang_name, progress)
115
+ end
116
+
117
+ # Conta ricorsivamente il numero di stringhe traducibili nella struttura dati.
118
+ def count_strings(data)
119
+ if data.is_a?(Hash)
120
+ data.values.sum { |v| count_strings(v) }
121
+ elsif data.is_a?(Array)
122
+ data.sum { |item| count_strings(item) }
123
+ elsif data.is_a?(String)
124
+ 1
125
+ else
126
+ 0
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BetterTranslate
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,64 @@
1
+ module BetterTranslate
2
+ class Writer
3
+ class << self
4
+ # Scrive il file di traduzione per una lingua target.
5
+ # Se il metodo di traduzione è :override, il file viene riscritto da zero;
6
+ # se è :incremental, il file esistente viene aggiornato inserendo le nuove traduzioni nelle posizioni corrette.
7
+ #
8
+ # @param translated_data [Hash] La struttura dati tradotta (ad es. { "sample" => { "valid" => "tradotto", "new_key" => "nuova traduzione" } }).
9
+ # @param target_lang_code [String] Codice della lingua target (es. "ru").
10
+ def write_translations(translated_data, target_lang_code)
11
+ output_folder = BetterTranslate.configuration.output_folder
12
+ output_file = File.join(output_folder, "#{target_lang_code}.yml")
13
+
14
+ # Riformatta la struttura per utilizzare il codice target come chiave principale.
15
+ output_content = if translated_data.is_a?(Hash) && translated_data.key?(BetterTranslate.configuration.source_language)
16
+ # Sostituisce la chiave della lingua di partenza con quella target.
17
+ { target_lang_code => translated_data[BetterTranslate.configuration.source_language] }
18
+ else
19
+ { target_lang_code => translated_data }
20
+ end
21
+
22
+ if BetterTranslate.configuration.translation_method.to_sym == :incremental && File.exist?(output_file)
23
+ existing_data = YAML.load_file(output_file)
24
+ merged = deep_merge(existing_data, output_content)
25
+ File.write(output_file, merged.to_yaml(line_width: -1))
26
+ puts "File aggiornato in modalità incremental: #{output_file}"
27
+ else
28
+ FileUtils.mkdir_p(output_folder) unless Dir.exist?(output_folder)
29
+ File.write(output_file, output_content.to_yaml(line_width: -1))
30
+ puts "File riscritto in modalità override: #{output_file}"
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ # Metodo di deep merge: unisce in modo ricorsivo i due hash.
37
+ # Se una chiave esiste in entrambi gli hash e i valori sono hash, li unisce ricorsivamente.
38
+ # Altrimenti, se la chiave esiste già nell'hash esistente, la mantiene e non la sovrascrive.
39
+ # Se la chiave non esiste, la aggiunge.
40
+ #
41
+ # @param existing [Hash] hash esistente (file corrente)
42
+ # @param new_data [Hash] nuovo hash con le traduzioni da unire
43
+ # @return [Hash] hash unito
44
+ def deep_merge(existing, new_data)
45
+ merged = existing.dup
46
+ new_data.each do |key, value|
47
+ if merged.key?(key)
48
+ if merged[key].is_a?(Hash) && value.is_a?(Hash)
49
+ merged[key] = deep_merge(merged[key], value)
50
+ else
51
+ # Se la chiave esiste già, non sovrascrivo il valore (modalità incrementale)
52
+ # oppure potresti decidere di aggiornare comunque, a seconda delle esigenze.
53
+ merged[key] = merged[key]
54
+ end
55
+ else
56
+ merged[key] = value
57
+ end
58
+ end
59
+ merged
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+ require "ruby-progressbar"
3
+
4
+ require "better_translate/version"
5
+ require "better_translate/translator"
6
+ require "better_translate/service"
7
+ require "better_translate/writer"
8
+
9
+ require 'better_translate/providers/base_provider'
10
+ require 'better_translate/providers/chatgpt_provider'
11
+ require 'better_translate/providers/gemini_provider'
12
+
13
+ module BetterTranslate
14
+ class << self
15
+ attr_accessor :configuration
16
+
17
+ # Metodo per configurare la gemma
18
+ def configure
19
+ self.configuration ||= OpenStruct.new
20
+ yield(configuration) if block_given?
21
+ end
22
+
23
+ # Metodo install per generare il file di configurazione (initializer)
24
+ def install
25
+ unless defined?(Rails) && Rails.respond_to?(:root)
26
+ puts "Il metodo install è disponibile solo in un'applicazione Rails."
27
+ return
28
+ end
29
+
30
+ # Costruisce il percorso della cartella template all'interno della gemma
31
+ source = File.expand_path("../generators/better_translate/templates/better_translate.rb", __dir__)
32
+ destination = File.join(Rails.root, "config", "initializers", "better_translate.rb")
33
+
34
+ if File.exist?(destination)
35
+ puts "Il file initializer esiste già: #{destination}"
36
+ else
37
+ FileUtils.mkdir_p(File.dirname(destination))
38
+ FileUtils.cp(source, destination)
39
+ puts "Initializer creato in: #{destination}"
40
+ end
41
+ end
42
+
43
+ def magic
44
+ puts "Metodo magic invocato: eseguirò la traduzione dei file..."
45
+
46
+ BetterTranslate::Translator.work
47
+ puts "Metodo magic invocato: Traduzione completata con successo!"
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,14 @@
1
+ require 'rails/generators'
2
+
3
+ module BetterTranslate
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('templates', __dir__)
7
+ desc "Genera il file config/initializers/better_translate.rb con la configurazione di default"
8
+
9
+ def copy_initializer
10
+ template "better_translate.rb", "config/initializers/better_translate.rb"
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,49 @@
1
+ BetterTranslate.configure do |config|
2
+ # Scegli il provider da utilizzare: :chatgpt oppure :gemini
3
+ config.provider = :chatgpt
4
+
5
+ # API key per OpenAI
6
+ config.openai_key = ENV.fetch("OPENAI_API_KEY") { "YOUR_OPENAI_API_KEY" }
7
+
8
+ # API key per Google Gemini
9
+ config.google_gemini_key = ENV.fetch("GOOGLE_GEMINI_KEY") { "YOUR_GOOGLE_GEMINI_KEY" }
10
+
11
+ # Lingua sorgente (ad esempio "en" se il file sorgente è in inglese)
12
+ config.source_language = "en"
13
+
14
+ # Lista delle lingue target (short_name e name)
15
+ config.target_languages = [
16
+ # { short_name: 'es', name: 'spagnolo' },
17
+ # { short_name: 'it', name: 'italiano' },
18
+ # { short_name: 'fr', name: 'francese' },
19
+ # { short_name: 'de', name: 'tedesco' },
20
+ # { short_name: 'pt', name: 'portoghese' },
21
+ { short_name: "ru", name: "russian" }
22
+ ]
23
+
24
+ # Esclusioni globali (percorsi in dot notation) da escludere per tutte le lingue
25
+ config.global_exclusions = [
26
+ "key.value"
27
+ ]
28
+
29
+ # Esclusioni specifiche per lingua
30
+ config.exclusions_per_language = {
31
+ "es" => [],
32
+ "it" => [],
33
+ "fr" => [],
34
+ "de" => [],
35
+ "pt" => [],
36
+ "ru" => []
37
+ }
38
+
39
+ # Percorso del file di input (ad es. en.yml)
40
+ config.input_file = Rails.root.join("config", "locales", "en.yml").to_s
41
+
42
+ # Cartella di output dove verranno salvati i file tradotti
43
+ config.output_folder = Rails.root.join("config", "locales", "translated").to_s
44
+
45
+ # Metodo di traduzione:
46
+ # - :override => rigenera tutte le traduzioni
47
+ # - :incremental => aggiorna solo le chiavi mancanti (o quelle che hanno subito modifiche)
48
+ config.translation_method = :override
49
+ end
metadata ADDED
@@ -0,0 +1,138 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: better_translate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - alessio_bussolari
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-03-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: yaml
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: httparty
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: ruby-progressbar
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.11'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.11'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '13.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '13.0'
83
+ description: "\nBetterTranslate è una gemma che consente di tradurre file YAML partendo
84
+ da una lingua sorgente verso una o più lingue target.\nLa gemma supporta differenti
85
+ provider di traduzione, attualmente ChatGPT (OpenAI) e Google Gemini, e permette
86
+ di scegliere\nla modalità di traduzione: \"override\" per rigenerare tutte le traduzioni
87
+ oppure \"incremental\" per aggiornare solo le chiavi mancanti.\n\nLa configurazione
88
+ della gemma è centralizzata tramite un initializer, dove è possibile definire API
89
+ key, lingue target, lingua sorgente,\nesclusioni di chiavi e la cartella di output.
90
+ BetterTranslate integra inoltre il monitoraggio del progresso della traduzione tramite
91
+ una progress bar.\n "
92
+ email:
93
+ - alessio.bussolari@pandev.it
94
+ executables: []
95
+ extensions: []
96
+ extra_rdoc_files: []
97
+ files:
98
+ - LICENSE.txt
99
+ - README.md
100
+ - lib/better_translate.rb
101
+ - lib/better_translate/providers/base_provider.rb
102
+ - lib/better_translate/providers/chatgpt_provider.rb
103
+ - lib/better_translate/providers/gemini_provider.rb
104
+ - lib/better_translate/service.rb
105
+ - lib/better_translate/translator.rb
106
+ - lib/better_translate/version.rb
107
+ - lib/better_translate/writer.rb
108
+ - lib/generators/better_translate/install_generator.rb
109
+ - lib/generators/better_translate/templates/better_translate.rb
110
+ homepage: https://github.com/alessiobussolari/better_translate
111
+ licenses:
112
+ - MIT
113
+ metadata:
114
+ allowed_push_host: https://rubygems.org
115
+ rubygems_mfa_required: 'true'
116
+ homepage_uri: https://github.com/alessiobussolari/better_translate
117
+ source_code_uri: https://github.com/alessiobussolari/better_translate
118
+ changelog_uri: https://github.com/alessiobussolari/better_translate/blob/main/CHANGELOG.md
119
+ post_install_message:
120
+ rdoc_options: []
121
+ require_paths:
122
+ - lib
123
+ required_ruby_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: 3.0.0
128
+ required_rubygems_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ requirements: []
134
+ rubygems_version: 3.5.11
135
+ signing_key:
136
+ specification_version: 4
137
+ summary: Gemma per tradurre file YAML in più lingue tramite provider (ChatGPT e Gemini)
138
+ test_files: []