i18nize 0.5.1 → 0.6

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: ecaecd54d2f036282dddadfefe26591090c54272cf6a5646fb12d53367509795
4
- data.tar.gz: '08adc947c1a7b46f2f7e3dc486d3429bb9e404ed9d7b61ab683a6813ee45cbd2'
3
+ metadata.gz: ed1bfd2cff604aa20337cfd2e87dd47985ab66d470ee13fa1241378e8c7613d2
4
+ data.tar.gz: 8e2a54ea7acb3ff57233944f81648f8243f732768278cd77478f7bf5fed08d35
5
5
  SHA512:
6
- metadata.gz: 0a32cac5c9df881264c7ae1688345410efa5ed64d8a3481526f83d2f4ef84f888af4e83fdce0af2da09f9f2594918d2606ffe31bd3c66e4a7af84f823c2443eb
7
- data.tar.gz: 68fa3a1028e87cf9965e20be6ab5b663c438b0b27ec3269fc8fc7a4543a59551f832d206e416cf79784e38cca474be09aa9ddc47d208bd581cf0aa830f0d4ce5
6
+ metadata.gz: f7322c2b6b1bc505090789774f340404186be3dcaed272629b19ab914bd36af3f8c1d50cde289ce29e203c60fc3273d5a8981c11060fdbfd571d261bc96803a3
7
+ data.tar.gz: ff89ec4d79479de9c40855916fc0a5dfa3f87a6e300459625edcfb7928aafb54ac15faec21e3a9e68d6a8c47543d716ac53a41620496363e86c7abb5314d00e4
data/CHANGELOG.md CHANGED
@@ -1,15 +1,19 @@
1
1
  # Changelog
2
2
 
3
- ## [Unreleased]
4
-
5
- ---
6
-
3
+ ## [0.6] - 2025-09-11
7
4
  ### Added
8
- ### Changed
9
- ### Removed
10
- ### Fixed
5
+ - CLI flag `--only_blank`: fills only missing or blank keys with a placeholder
6
+ (`<locale>.<full.key> missing`) instead of translating with DeepL.
7
+ - Environment variable `I18NIZE_ALLOW_EMPTY=1`: skips keys where the source value is empty
8
+ or whitespace-only, preventing them from being copied/translated.
11
9
 
12
- ---
10
+ ### Changed
11
+ - CLI parsing improved: `--from` can now be used **before or after** the target locale.
12
+ Examples:
13
+ ```bash
14
+ i18nize cs --from de
15
+ i18nize --from de cs
16
+ ````
13
17
 
14
18
  ---
15
19
 
data/README.md CHANGED
@@ -1,5 +1,9 @@
1
+
1
2
  # i18nize
2
3
 
4
+ [![CI](https://github.com/nikolas2145/i18nize/actions/workflows/main.yml/badge.svg)](https://github.com/nikolas2145/i18nize/actions/workflows/main.yml)
5
+ [![Gem Version](https://badge.fury.io/rb/i18nize.svg)](https://badge.fury.io/rb/i18nize)
6
+
3
7
  🧠 Automatically fills in missing I18n YAML keys using DeepL translation API.
4
8
  Designed to streamline multi-language support in Ruby and Rails projects.
5
9
 
@@ -8,6 +12,7 @@ Designed to streamline multi-language support in Ruby and Rails projects.
8
12
  * Detects missing or empty translation keys in locale files
9
13
  * Supports multiple YAML files and nested directories (e.g. `config/locales/api/en.yml`)
10
14
  * Automatically translates from a source locale (**default: `en`**) to a target (e.g. `cs`)
15
+ * **Placeholder mode** to fill only blank/missing keys without DeepL (`--only_blank`)
11
16
  * Integrates with DeepL API (Free or Pro)
12
17
  * Safely merges translations into corresponding `*.yml` files
13
18
  * Handles structural conflicts by overwriting target with source truth
@@ -20,7 +25,7 @@ Add this line to your application's Gemfile:
20
25
 
21
26
  ```ruby
22
27
  gem "i18nize"
23
- ```
28
+ ````
24
29
 
25
30
  Then run:
26
31
 
@@ -76,6 +81,31 @@ i18nize cs --missing de
76
81
 
77
82
  This mode only lists missing keys, no translations are written.
78
83
 
84
+ ### 4. Fill placeholders for blank/missing keys (no DeepL)
85
+
86
+ ```bash
87
+ # Insert placeholders instead of translating
88
+ i18nize cs --only_blank
89
+ ```
90
+
91
+ This scans all keys in the **source** locale (default `en`) and, for any **missing or blank** value in the target locale, inserts a placeholder:
92
+
93
+ ```
94
+ <locale>.<full.dot.key> missing
95
+ ```
96
+
97
+ Example:
98
+
99
+ ```yaml
100
+ en:
101
+ test:
102
+ title: "Testing"
103
+ cs:
104
+ test:
105
+ title: "cs.test.title missing"
106
+ ```
107
+
108
+ Existing non-blank values in the target are left untouched.
79
109
 
80
110
  ## 🛡️ Character limit check
81
111
 
@@ -132,8 +162,11 @@ For now, configuration is via CLI flags and environment variables:
132
162
 
133
163
  * `--from LANG` (default `en`)
134
164
  * `--missing [FROM]` (list missing keys only)
135
- * `DEEPL_API_KEY` (required)
165
+ * `--only_blank` (fill only blank/missing keys with placeholders, no DeepL)
166
+ * `DEEPL_API_KEY` (required for translation mode)
136
167
  * `DEEPL_ENDPOINT` (optional, only for Pro)
168
+ * `I18NIZE_ALLOW_EMPTY == "1"` → **skip empty/whitespace-only values** in the source when inserting or translating
169
+ (i.e., if a source value is `""` or `" "` it will be ignored and not propagated to the target)
137
170
 
138
171
  ---
139
172
 
@@ -142,5 +175,5 @@ For now, configuration is via CLI flags and environment variables:
142
175
  * RSpec test suite
143
176
  * YAML key sorting / format preservation
144
177
  * Richer conflict resolution strategies (configurable overwrite / skip)
145
- * Use custom char limit
178
+ * Use custom char limit
146
179
 
data/lib/i18nize/cli.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "optparse"
4
-
5
4
  require "i18nize/translator"
6
5
  require "i18nize/inserter"
7
6
  require "i18nize/comparer"
8
7
 
9
8
  module I18nize
9
+ # CLI for i18nize
10
10
  class CLI
11
11
  def self.run(argv)
12
12
  new(argv).run
@@ -16,107 +16,102 @@ module I18nize
16
16
  @argv = argv.dup
17
17
  @options = {
18
18
  from: "en",
19
- mode: :translate,
19
+ mode: :translate, # :translate | :missing | :only_blank
20
20
  missing_from: nil
21
21
  }
22
22
  end
23
23
 
24
24
  def run
25
- print_help_and_exit if @argv.empty? || help_requested?
26
-
27
- first = @argv.first
28
- parse_flags!(@argv[1..] || [])
29
-
30
- to_locale = parse_positional_locale!(first)
25
+ remaining = parse_flags!(@argv)
26
+ abort usage unless remaining.any?
27
+ to_locale = remaining.shift.strip
31
28
 
32
- if @options[:mode] == :missing
29
+ case @options[:mode]
30
+ when :missing
33
31
  from = @options[:missing_from] || @options[:from]
34
32
  show_missing_translations(from:, to: to_locale)
35
- return 0
33
+ when :only_blank
34
+ run_only_blank(to_locale)
35
+ else
36
+ run_translation(to_locale)
36
37
  end
37
-
38
- run_translation(to_locale)
39
38
  0
40
39
  rescue OptionParser::InvalidOption => e
41
40
  warn red(e.message)
42
- print_help_and_exit(2)
41
+ puts usage
42
+ 2
43
43
  rescue SystemExit => e
44
44
  raise e
45
45
  rescue => e
46
46
  warn red("Error: #{e.class}: #{e.message}")
47
47
  e.backtrace.each { |l| warn l } if ENV["I18NIZE_DEBUG"] == "1"
48
- exit 1
48
+ 1
49
49
  end
50
50
 
51
51
  private
52
52
 
53
- def help_requested?
54
- (@argv & %w[-h --help help]).any?
55
- end
56
-
57
- def parse_positional_locale!(arg)
58
- abort yellow("Usage: i18nize <to_locale> [--from en] [--missing [FROM]]") unless arg
59
- arg.strip
60
- end
61
-
62
- def parse_flags!(rest)
63
- OptionParser.new do |o|
53
+ def parse_flags!(args)
54
+ parser = OptionParser.new do |o|
64
55
  o.banner = "Usage: i18nize <to_locale> [options]"
65
- o.on("--from LANG", "Source language for comparison/translation (default: en)") { |v| @options[:from] = v }
66
-
56
+ o.on("--from LANG", "Source language (default: en)") { |v| @options[:from] = v }
67
57
  o.on("--missing", "--missing [FROM]", "List missing keys only; optionally specify source locale") do |from|
68
58
  @options[:mode] = :missing
69
59
  @options[:missing_from] = from if from && !from.strip.empty?
70
60
  end
61
+ o.on("--only_blank", "Fill only missing/blank keys with '<locale>.<full.key> missing'") do
62
+ @options[:mode] = :only_blank
63
+ end
64
+ o.on("-h", "--help", "Show help") { puts usage; exit 0 }
65
+ end
71
66
 
72
- o.on("-h", "--help", "Show help") { print_help_and_exit }
73
- end.parse!(rest)
67
+ parser.parse!(args)
68
+ args
74
69
  end
75
70
 
76
71
  def show_missing_translations(from:, to:)
77
72
  load_rails_if_available
78
73
  puts cyan("🔍 Missing keys for #{to} (from #{from})")
79
-
80
74
  missing = I18nize::Comparer.missing_translations(from_locale: from, to_locale: to)
81
-
82
75
  if missing.empty?
83
76
  puts green("✅ No missing translations.")
84
77
  return
85
78
  end
86
-
87
- total_keys = missing.total_keys
88
- puts yellow("⚠️ #{total_keys} missing #{total_keys == 1 ? 'key' : 'keys'}:")
89
-
79
+ total = missing.total_keys
80
+ puts yellow("⚠️ #{total} missing #{total == 1 ? 'key' : 'keys'}:")
90
81
  missing.values_by_file.each do |file, keys_hash|
91
82
  puts " #{file}:"
92
- keys_hash.keys.sort.each do |k|
93
- puts " - #{k.sub(/^#{from}\./, '')}"
94
- end
83
+ keys_hash.keys.sort.each { |k| puts " - #{k.sub(/^#{Regexp.escape(from)}\./, "")}" }
95
84
  end
96
85
  end
97
86
 
98
- def run_translation(to_locale)
87
+ def run_only_blank(to_locale)
99
88
  load_env_files
89
+ load_rails_if_available
90
+ puts cyan("Filling only blank/missing keys: from #{@options[:from]} → #{to_locale}")
91
+ I18nize::Inserter.insert_only_blank(
92
+ from_locale: @options[:from],
93
+ to_locale: to_locale
94
+ )
95
+ puts green("✅ Placeholders inserted for blank/missing keys.")
96
+ end
100
97
 
98
+ def run_translation(to_locale)
99
+ load_env_files
101
100
  api_key = ENV["DEEPL_API_KEY"]
102
101
  abort red("Missing DEEPL_API_KEY env variable") if api_key.to_s.strip.empty?
103
-
104
102
  load_rails_if_available
105
103
 
106
104
  puts cyan("Starting translation: from #{@options[:from]} → #{to_locale}")
107
-
108
105
  translator = I18nize::Translator.new(
109
106
  auth_key: api_key,
110
107
  from_lang: @options[:from].upcase,
111
108
  to_lang: to_locale.upcase
112
109
  )
113
-
114
110
  I18nize::Inserter.insert_missing(
115
111
  from_locale: @options[:from],
116
112
  to_locale: to_locale,
117
113
  translator: translator
118
114
  )
119
-
120
115
  puts green("✅ Translation completed.")
121
116
  end
122
117
 
@@ -124,18 +119,37 @@ module I18nize
124
119
  begin
125
120
  require "dotenv/load"
126
121
  rescue LoadError
127
- # Ignore
128
122
  end
129
123
  end
130
124
 
131
125
  def load_rails_if_available
132
126
  return if defined?(Rails)
133
127
 
134
- if File.exist?("config/environment.rb")
135
- require_relative "../../config/environment"
136
- end
128
+ require_relative "../../config/environment" if File.exist?("config/environment.rb")
129
+
137
130
  rescue LoadError
138
- # Ignore
131
+ # Ignored
132
+ end
133
+
134
+ def usage
135
+ <<~HELP
136
+ Usage:
137
+ i18nize <to_locale> [options]
138
+
139
+ Examples:
140
+ i18nize cs # translate missing from en -> cs
141
+ i18nize cs --from de # translate missing from de -> cs
142
+ i18nize --from de cs # flags can be before or after the locale
143
+ i18nize cs --missing # list missing keys for cs (from en)
144
+ i18nize cs --missing de # list missing keys for cs (from de)
145
+ i18nize cs --only_blank # fill only blank/missing keys with placeholders
146
+
147
+ Options:
148
+ --from LANG Source language (default: en)
149
+ --missing [FROM] Only list missing keys (optional override of source)
150
+ --only_blank Insert '<locale>.<full.key> missing' for blank/missing keys
151
+ -h, --help Show this help
152
+ HELP
139
153
  end
140
154
 
141
155
  def color(text, code) = "\e[#{code}m#{text}\e[0m"
@@ -147,24 +161,5 @@ module I18nize
147
161
  def yellow(text) = color(text, 33)
148
162
 
149
163
  def cyan(text) = color(text, 36)
150
-
151
- def print_help_and_exit(code = 0)
152
- puts <<~HELP
153
- Usage:
154
- i18nize <to_locale> [options]
155
-
156
- Examples:
157
- i18nize cs # translate missing from en -> cs
158
- i18nize cs --from de # translate missing from de -> cs
159
- i18nize cs --missing # list missing keys for cs (from en)
160
- i18nize cs --missing de # list missing keys for cs (from de)
161
-
162
- Options:
163
- --from LANG Source language (default: en)
164
- --missing [FROM] Only list missing keys (optional override of source)
165
- -h, --help Show this help
166
- HELP
167
- exit code
168
- end
169
164
  end
170
165
  end
@@ -4,8 +4,9 @@ require_relative "loader"
4
4
  require_relative "missing_set"
5
5
 
6
6
  module I18nize
7
+ # Small utility to compare translations from one locale to another
7
8
  class Comparer
8
- def self.missing_translations(from_locale: "en", to_locale:)
9
+ def self.missing_translations(to_locale:, from_locale: "en") # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
9
10
  from_data = Loader.load_per_file(locale: from_locale)
10
11
  to_data = Loader.load_per_file(locale: to_locale)
11
12
 
@@ -37,7 +38,7 @@ module I18nize
37
38
  MissingSet.new(from_locale: from_locale, to_locale: to_locale, data: result)
38
39
  end
39
40
 
40
- def self.missing_keys(from_locale: "en", to_locale:)
41
+ def self.missing_keys(to_locale:, from_locale: "en")
41
42
  missing_translations(from_locale: from_locale, to_locale: to_locale).keys_by_file
42
43
  end
43
44
  end
@@ -2,13 +2,15 @@
2
2
 
3
3
  require "yaml"
4
4
  require "fileutils"
5
+ require "byebug"
5
6
  require_relative "comparer"
7
+ require_relative "loader"
6
8
 
7
9
  module I18nize
8
10
  class Inserter
9
11
  CONFLICT_POLICY = :overwrite # :overwrite | :skip
10
12
 
11
- def self.insert_missing(from_locale: "en", to_locale:, base_path: "config/locales", translator: nil)
13
+ def self.insert_missing(to_locale:, from_locale: "en", base_path: "config/locales", translator: nil)
12
14
  missing_data = Comparer.missing_translations(from_locale: from_locale, to_locale: to_locale)
13
15
 
14
16
  if translator
@@ -26,7 +28,7 @@ module I18nize
26
28
  overwrites = []
27
29
 
28
30
  missing_data.data.each do |from_rel_path, translations|
29
- dirname = File.dirname(from_rel_path)
31
+ dirname = File.dirname(from_rel_path)
30
32
  filename = File.basename(from_rel_path)
31
33
 
32
34
  locale_re = /(^|[._])#{Regexp.escape(from_locale)}\.(ya?ml)$/
@@ -40,7 +42,7 @@ module I18nize
40
42
  translation_map =
41
43
  if translator
42
44
  src_values = translations.values
43
- translated_values = translator.translate_texts(src_values) # => pole!
45
+ translated_values = translator.translate_texts(src_values) # returns array
44
46
  translations.keys.zip(translated_values).to_h
45
47
  else
46
48
  translations
@@ -57,15 +59,70 @@ module I18nize
57
59
  puts "\e[32m[i18nize] Inserted #{translation_map.size} keys into #{to_full_path}\e[0m"
58
60
  end
59
61
 
60
- if overwrites.any?
62
+ return unless overwrites.any?
61
63
  puts "\n\e[33m[i18nize] Overwrote #{overwrites.size} scalar node(s) to create nested structure:\e[0m"
62
64
  overwrites.each do |c|
63
65
  puts " \e[33m- #{c[:file]}: #{c[:locale]}.#{c[:path].join('.')}\e[0m (was: #{c[:existing_class]})"
64
66
  end
67
+
68
+ end
69
+
70
+ # NEW: fill only missing/blank values with "<locale>.<full.key> missing"
71
+ def self.insert_only_blank(to_locale:, from_locale: "en", base_path: "config/locales")
72
+ from_data = Loader.load_per_file(locale: from_locale, base_path: base_path)
73
+ # to_data = Loader.load_per_file(locale: to_locale, base_path: base_path)
74
+
75
+ updated_files = 0
76
+ overwrites = []
77
+
78
+ from_data.each do |from_rel_path, from_keys|
79
+ dirname = File.dirname(from_rel_path)
80
+ filename = File.basename(from_rel_path)
81
+ locale_re = /(^|[._])#{Regexp.escape(from_locale)}\.(ya?ml)$/
82
+ new_filename = filename.sub(locale_re) { "#{Regexp.last_match(1)}#{to_locale}.#{Regexp.last_match(2)}" }
83
+ to_rel_path = dirname == "." || dirname.empty? ? new_filename : File.join(dirname, new_filename)
84
+ to_full_path = File.join(base_path, to_rel_path)
85
+
86
+ existing = File.exist?(to_full_path) ? YAML.load_file(to_full_path) : {}
87
+ existing[to_locale] ||= {}
88
+
89
+ changes = 0
90
+
91
+ from_keys.each_key do |from_full_key|
92
+ to_full_key = from_full_key.sub(/^#{Regexp.escape(from_locale)}\./, "#{to_locale}.")
93
+ path = to_full_key.sub(/^#{Regexp.escape(to_locale)}\./, "").split(".")
94
+ current = dig_nested(existing[to_locale], path)
95
+ next if current.to_s.strip.empty? && ENV["I18NIZE_ALLOW_EMPTY"] == "1"
96
+ next unless current.nil? || current.to_s.strip.empty?
97
+
98
+ placeholder = "#{to_full_key} missing"
99
+ insert_nested(existing[to_locale], path, placeholder, overwrites, to_rel_path, to_locale, :overwrite)
100
+ changes += 1
101
+ end
102
+
103
+ next unless changes.positive?
104
+
105
+ FileUtils.mkdir_p(File.dirname(to_full_path))
106
+ File.write(to_full_path, existing.to_yaml(line_width: -1))
107
+ updated_files += 1
108
+ puts "\e[32m[i18nize] Inserted #{changes} placeholder#{changes == 1 ? '' : 's'} into #{to_full_path}\e[0m"
109
+ end
110
+
111
+ puts "\e[90m[i18nize] No blank or missing keys found.\e[0m" if updated_files.zero?
112
+
113
+ return unless overwrites.any?
114
+
115
+ puts "\n\e[33m[i18nize] Overwrote #{overwrites.size} scalar node(s) while creating nested structure:\e[0m"
116
+ overwrites.each do |c|
117
+ puts " \e[33m- #{c[:file]}: #{c[:locale]}.#{c[:path].join('.')}\e[0m (was: #{c[:existing_class]})"
65
118
  end
66
119
  end
67
120
 
68
- # conflict_policy: :overwrite (replace scalar with {}), :skip (leave as is)
121
+ def self.dig_nested(hash, path)
122
+ path.reduce(hash) { |h, k| h.is_a?(Hash) ? h[k] : nil }
123
+ end
124
+
125
+ # conflict_policy: :overwrite (replace scalar with {}), :skip
69
126
  def self.insert_nested(base, keys, value, overwrites, file, locale, conflict_policy)
70
127
  key = keys.shift
71
128
 
@@ -79,18 +136,15 @@ module I18nize
79
136
  case cur
80
137
  when nil
81
138
  base[key] = {}
82
- insert_nested(base[key], keys, value, overwrites, file, locale, conflict_policy)
139
+ return insert_nested(base[key], keys, value, overwrites, file, locale, conflict_policy)
83
140
  when Hash
84
- insert_nested(cur, keys, value, overwrites, file, locale, conflict_policy)
141
+ return insert_nested(cur, keys, value, overwrites, file, locale, conflict_policy)
85
142
  else
86
- if conflict_policy == :overwrite
143
+ return false unless conflict_policy == :overwrite
87
144
  overwrites << { file: file, locale: locale, path: [key, *keys], existing_class: cur.class.to_s }
88
145
  base[key] = {}
89
- insert_nested(base[key], keys, value, overwrites, file, locale, conflict_policy)
90
- else
91
- # :skip
92
- false
93
- end
146
+ return insert_nested(base[key], keys, value, overwrites, file, locale, conflict_policy)
147
+
94
148
  end
95
149
  end
96
150
  end
@@ -3,6 +3,7 @@
3
3
  require "yaml"
4
4
 
5
5
  module I18nize
6
+ # Loader for i18nize
6
7
  class Loader
7
8
  def self.load_per_file(locale: "en", base_path: "config/locales")
8
9
  files = Dir.glob(File.join(base_path, "**", "*.yml")).select do |f|
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module I18nize
4
- require "byebug"
4
+ # Set of missing translations
5
5
  class MissingSet
6
6
  attr_reader :from_locale, :to_locale, :data
7
7
 
@@ -4,14 +4,15 @@ require "uri"
4
4
  require "json"
5
5
 
6
6
  module I18nize
7
+ # Translator for i18nize
7
8
  class Translator
8
9
  ENDPOINT = ENV.fetch("DEEPL_ENDPOINT", "https://api-free.deepl.com/v2/translate")
9
10
  PLACEHOLDER_RE = /%{\s*[^}]+\s*}/
10
11
 
11
12
  def initialize(auth_key:, from_lang: "EN", to_lang:)
12
- @auth_key = auth_key
13
+ @auth_key = auth_key
13
14
  @from_lang = from_lang
14
- @to_lang = to_lang
15
+ @to_lang = to_lang
15
16
  end
16
17
 
17
18
  def translate_texts(texts)
@@ -30,7 +31,7 @@ module I18nize
30
31
  body_params = [
31
32
  ["auth_key", @auth_key],
32
33
  ["source_lang", @from_lang],
33
- ["target_lang", @to_lang],
34
+ ["target_lang", @to_lang]
34
35
  ] + protected.map { |text| ["text", text] }
35
36
 
36
37
  req = Net::HTTP::Post.new(uri)
@@ -43,7 +44,7 @@ module I18nize
43
44
  json = JSON.parse(res.body)
44
45
  out = json["translations"].map { |t| t["text"] }
45
46
 
46
- out.map { |s| s.gsub(/__I18NIZE_PLH_(\d+)__/) { placeholders[$1.to_i] } }
47
+ out.map { |s| s.gsub(/__I18NIZE_PLH_(\d+)__/) { placeholders[::Regexp.last_match(1).to_i] } }
47
48
  end
48
49
  end
49
50
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module I18nize
4
- VERSION = "0.5.1"
4
+ VERSION = "0.6"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: i18nize
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: '0.6'
5
5
  platform: ruby
6
6
  authors:
7
7
  - nikolas2145
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-09-09 00:00:00.000000000 Z
11
+ date: 2025-09-11 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: "i18nize helps Ruby and Rails projects stay multilingual by automatically
14
14
  filling in \nmissing translations in I18n YAML locale files. It scans for missing