neeto-translate-cli 0.1.8.beta0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0c73059ad20700c02e1403314dd4d02883a0ecb44eb7844f853703486b3d31d7
4
- data.tar.gz: '017610084ab7ac9d466e1d4a841de80f5101e6bf04308e9e499aab1862570ab6'
3
+ metadata.gz: 19601fee62f445e2d199a073ab27dd65f1e5cb01364ca2acd92acfac9e290e4c
4
+ data.tar.gz: 77c013b6ec3d310416e8d6e89bee8da9ab340ee9da4b2783b3d2debebef1e32e
5
5
  SHA512:
6
- metadata.gz: afb0a7b73fa6f569a84579ea6bb981434adab7545cd25cf21571e691a4e99e3398d7bb72d4cc16b7f11a2a93006919ed1445aa8ee83ba475abe5b675200508e0
7
- data.tar.gz: 5c120b5eaf309f47239b26b48e462626448d6097ceffeebcc3dc206d4254f9df1e986e5ae759ff30487bc8c8e5de323a6066e721283e8f51dea08914ba61718d
6
+ metadata.gz: 176e1e1dae72b2ceebac27716bda5eca56d798238cd8632a15e6806155369cf16d7fba50c9bb0df2749a756ad2858d69fb2f4da85e56913d618f87807be63a69
7
+ data.tar.gz: b3ce3265a73a5254b249ef9192d0c93660e320a7470ce9c9c7fc95a1059437afa04562a2092d3f46c6b37380fd4b404101d2a533534fa604d9d92f1a4c93606e
@@ -6,7 +6,7 @@ require "optparse"
6
6
 
7
7
  module NeetoTranslateCli
8
8
  class CLI
9
- DEFAULT_LANGUAGES = "en,ar,bg,ca,zh-cn,zh-tw,hr,cs,da,nl,et,fil,fi,fr,de,hi,id,it,ja,ko,pl,pt,pt-br,ro,ru,sk,sl,es,es-mx,sv,th,tr,uk,vi"
9
+ DEFAULT_LANGUAGES = "en,ar,bg,ca,zh-CN,zh-TW,hr,cs,da,nl,et,fil,fi,fr,de,hi,id,it,ja,ko,pl,pt,pt-BR,ro,ru,sk,sl,es,es-MX,sv,th,tr,uk,vi"
10
10
  NEETO_TRANSLATE_URL = "https://translate.neeto.com"
11
11
  DEFAULT_BACKEND_LOCALE_PATH = "config/locales"
12
12
  DEFAULT_FRONTEND_LOCALE_PATH = "app/javascript/src/translations"
@@ -31,7 +31,8 @@ module NeetoTranslateCli
31
31
  frontend: DEFAULT_FRONTEND_LOCALE_PATH,
32
32
  backend: DEFAULT_BACKEND_LOCALE_PATH,
33
33
  default_languages: (ENV["DEFAULT_LANGUAGES"] || DEFAULT_LANGUAGES).to_s.split(","),
34
- repo: `git rev-parse --show-toplevel`.split("/").last.strip
34
+ repo: `git rev-parse --show-toplevel`.split("/").last.strip,
35
+ branch: "main"
35
36
  }
36
37
 
37
38
  OptionParser.new do |opts|
@@ -43,6 +44,11 @@ module NeetoTranslateCli
43
44
  opts.on("--repo NAME", "Name of the GitHub repository (eg: neetozone/neeto-cal-web).") do |path|
44
45
  options[:repo] = path
45
46
  end
47
+ opts.on("--branch NAME", "Base branch to which the PR should be created") { |branch| options[:branch] = branch}
48
+
49
+ # This arg is explicitly added to handle translations in neeto-website and bigbinary-website.
50
+ # Usage: --strategy next-i18next
51
+ opts.on("--strategy NAME", "Name of the i18next package used to generate the translations") { |name| options[:strategy] = name }
46
52
  end.parse!(args)
47
53
 
48
54
  options
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+
5
+ module NeetoTranslateCli
6
+ module NextI18next
7
+ class PayloadBuilder
8
+ attr_reader :options, :updated_keys
9
+
10
+ def initialize(options)
11
+ @options = options
12
+ commit_id = git_commit_id
13
+ @updated_keys = commit_id.empty? ? { frontend: {} } : find_updated_keys(commit_id)
14
+ end
15
+
16
+ def process!
17
+ {
18
+ frontend: {
19
+ en: flatten_hash_with_colon(frontend_translations[:en]),
20
+ missing_keys: find_missing_keys
21
+ },
22
+ metadata: {
23
+ repo: options[:repo],
24
+ frontend: options[:frontend],
25
+ strategy: options[:strategy],
26
+ branch: options[:branch],
27
+ }
28
+ }
29
+ end
30
+
31
+ def no_new_changes?(payload)
32
+ payload[:frontend][:missing_keys].values.all?(&:empty?)
33
+ end
34
+
35
+ private
36
+
37
+ def git_commit_id
38
+ `git log --grep="[neeto-translate]" --fixed-strings -n 1 --pretty=format:"%H"`.strip
39
+ end
40
+
41
+ def find_updated_keys(commit_id)
42
+ updated_frontend_keys = {}
43
+ frontend_translations[:en].each do |file_path, content|
44
+ relative_path_from_pwd = Pathname.new(file_path).relative_path_from(Pathname.new(Dir.pwd)).to_s
45
+ previous_content = `git show #{commit_id}:#{relative_path_from_pwd}`
46
+ next if previous_content.empty?
47
+
48
+ previous_json = JSON.parse(previous_content)
49
+ flat_previous_json = flatten_hash(previous_json)
50
+ flat_current_json = flatten_hash(content)
51
+
52
+ updated_keys_for_file = flat_current_json.keys.select do |key|
53
+ flat_previous_json.key?(key) && flat_current_json[key] != flat_previous_json[key]
54
+ end
55
+
56
+ next if updated_keys_for_file.empty?
57
+
58
+ relative_path_from_en_dir = Pathname.new(file_path)
59
+ .relative_path_from(Pathname.new(File.expand_path(File.join(options[:frontend], "en")))).to_s
60
+ path_without_ext = relative_path_from_en_dir.chomp(File.extname(relative_path_from_en_dir))
61
+ updated_frontend_keys[path_without_ext] = updated_keys_for_file
62
+ end
63
+ { frontend: updated_frontend_keys }
64
+ end
65
+
66
+ def find_missing_keys
67
+ missing_keys = {}
68
+ base_translations = frontend_translations[:en]
69
+
70
+ options[:default_languages].each do |lang|
71
+ missing_keys[lang] = []
72
+ base_translations.each do |base_file_path, base_content|
73
+ lang_file_path = "#{options[:frontend]}/#{lang}/#{base_file_path}.json"
74
+
75
+ base_keys = flatten_hash(base_content).keys
76
+ lang_keys = File.file?(lang_file_path) ? flatten_hash(load_json(lang_file_path)).keys : []
77
+
78
+ missing_in_file = (base_keys - lang_keys).uniq
79
+ missing_keys[lang].concat(missing_in_file.map { |key| "#{base_file_path}:#{key}" })
80
+ end
81
+ end
82
+
83
+ missing_keys
84
+ end
85
+
86
+ def frontend_translations
87
+ return @_frontend_translations if defined?(@_frontend_translations)
88
+
89
+ all_files = Dir.glob("#{options[:frontend]}/en/**/*").select { |path| File.file?(path) }
90
+ @_frontend_translations = { en: {} }
91
+
92
+ all_files.each do |path|
93
+ lang_key = path.gsub("#{options[:frontend]}/en/", "").gsub(".json", "")
94
+ @_frontend_translations[:en][lang_key] = load_json(path)
95
+ end
96
+
97
+ @_frontend_translations
98
+ end
99
+
100
+ def load_json(file_path)
101
+ return {} unless File.file?(file_path)
102
+
103
+ JSON.parse(File.read(file_path, encoding: "utf-8"))
104
+ end
105
+
106
+ def flatten_hash(hash, prefix = nil)
107
+ hash.each_with_object({}) do |(key, value), result|
108
+ current_key = prefix ? "#{prefix}.#{key}" : key.to_s
109
+ if value.is_a?(Hash)
110
+ result.merge!(flatten_hash(value, current_key))
111
+ else
112
+ result[current_key] = value
113
+ end
114
+ end
115
+ end
116
+
117
+ def flatten_hash_with_colon(hash)
118
+ hash.flat_map do |file_key, file_content|
119
+ flatten_hash(file_content).map do |translation_key, translation_value|
120
+ ["#{file_key}:#{translation_key}", translation_value]
121
+ end
122
+ end.to_h
123
+ end
124
+ end
125
+ end
126
+ end
@@ -18,7 +18,8 @@ module NeetoTranslateCli
18
18
  metadata: {
19
19
  repo: options[:repo],
20
20
  frontend: options[:frontend],
21
- backend: options[:backend]
21
+ backend: options[:backend],
22
+ branch: options[:branch]
22
23
  }
23
24
  }
24
25
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "api"
4
4
  require_relative "payload_builder"
5
+ require_relative "next_i18next/payload_builder"
5
6
 
6
7
  module NeetoTranslateCli
7
8
  class Translator
@@ -19,7 +20,9 @@ module NeetoTranslateCli
19
20
  private
20
21
 
21
22
  def translate!
22
- payload_builder = PayloadBuilder.new(options)
23
+ payload_builder = options[:strategy] == "next-i18next" ?
24
+ NeetoTranslateCli::NextI18next::PayloadBuilder.new(options)
25
+ : PayloadBuilder.new(options)
23
26
  payload = payload_builder.process!
24
27
 
25
28
  if payload_builder.no_new_changes?(payload)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module NeetoTranslateCli
4
- VERSION = "0.1.8.beta0"
4
+ VERSION = "0.2.0"
5
5
  end
@@ -13,17 +13,17 @@ class NeetoTranslateCli::CLITest < Minitest::Test
13
13
  def test_start_with_default_options
14
14
  cli = NeetoTranslateCli::CLI.new([])
15
15
  options = cli.send(:parse_options, [])
16
-
16
+
17
17
  assert_equal "app/javascript/src/translations", options[:frontend]
18
18
  assert_equal "config/locales", options[:backend]
19
- assert_equal %w[en fr de es], options[:default_languages]
19
+ assert_equal ::NeetoTranslateCli::CLI::DEFAULT_LANGUAGES.split(","), options[:default_languages]
20
20
  assert_equal @original_git_repo, options[:repo]
21
21
  end
22
22
 
23
23
  def test_start_with_custom_frontend_path
24
24
  cli = NeetoTranslateCli::CLI.new([])
25
25
  options = cli.send(:parse_options, ["--frontend", "custom/frontend/path"])
26
-
26
+
27
27
  assert_equal "custom/frontend/path", options[:frontend]
28
28
  assert_equal "config/locales", options[:backend]
29
29
  end
@@ -31,7 +31,7 @@ class NeetoTranslateCli::CLITest < Minitest::Test
31
31
  def test_start_with_custom_backend_path
32
32
  cli = NeetoTranslateCli::CLI.new([])
33
33
  options = cli.send(:parse_options, ["--backend", "custom/backend/path"])
34
-
34
+
35
35
  assert_equal "app/javascript/src/translations", options[:frontend]
36
36
  assert_equal "custom/backend/path", options[:backend]
37
37
  end
@@ -39,26 +39,26 @@ class NeetoTranslateCli::CLITest < Minitest::Test
39
39
  def test_start_with_custom_languages
40
40
  cli = NeetoTranslateCli::CLI.new([])
41
41
  options = cli.send(:parse_options, ["--defaults", "ja,ko,zh"])
42
-
42
+
43
43
  assert_equal %w[ja ko zh], options[:default_languages]
44
44
  end
45
45
 
46
46
  def test_start_with_custom_repo
47
47
  cli = NeetoTranslateCli::CLI.new([])
48
48
  options = cli.send(:parse_options, ["--repo", "neetozone/custom-repo"])
49
-
49
+
50
50
  assert_equal "neetozone/custom-repo", options[:repo]
51
51
  end
52
52
 
53
53
  def test_start_with_all_custom_options
54
54
  cli = NeetoTranslateCli::CLI.new([])
55
55
  options = cli.send(:parse_options, [
56
- "--frontend", "custom/frontend",
57
- "--backend", "custom/backend",
58
- "--defaults", "ja,ko",
59
- "--repo", "neetozone/test-repo"
60
- ])
61
-
56
+ "--frontend", "custom/frontend",
57
+ "--backend", "custom/backend",
58
+ "--defaults", "ja,ko",
59
+ "--repo", "neetozone/test-repo"
60
+ ])
61
+
62
62
  assert_equal "custom/frontend", options[:frontend]
63
63
  assert_equal "custom/backend", options[:backend]
64
64
  assert_equal %w[ja ko], options[:default_languages]
@@ -69,26 +69,26 @@ class NeetoTranslateCli::CLITest < Minitest::Test
69
69
  ENV["DEFAULT_LANGUAGES"] = "ja,ko,zh"
70
70
  cli = NeetoTranslateCli::CLI.new([])
71
71
  options = cli.send(:parse_options, [])
72
-
72
+
73
73
  assert_equal %w[ja ko zh], options[:default_languages]
74
74
  end
75
75
 
76
76
  def test_run_calls_translator
77
77
  mock_translator = Minitest::Mock.new
78
78
  mock_translator.expect :process!, nil
79
-
79
+
80
80
  options = {
81
81
  frontend: "test/fixtures/frontend",
82
82
  backend: "test/fixtures/backend",
83
83
  default_languages: %w[es de],
84
84
  repo: "test-repo"
85
85
  }
86
-
86
+
87
87
  NeetoTranslateCli::Translator.stub :new, mock_translator do
88
88
  cli = NeetoTranslateCli::CLI.new([])
89
89
  cli.send(:run_with_options, options)
90
90
  end
91
-
91
+
92
92
  mock_translator.verify
93
93
  end
94
94
 
@@ -98,4 +98,4 @@ class NeetoTranslateCli::CLITest < Minitest::Test
98
98
  cli = NeetoTranslateCli::CLI.new(args)
99
99
  cli.send(:parse_options, args)
100
100
  end
101
- end
101
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: neeto-translate-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8.beta0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Abhay V Ashokan
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-08-01 00:00:00.000000000 Z
11
+ date: 2025-09-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -40,6 +40,7 @@ files:
40
40
  - exe/neeto-translate-cli
41
41
  - lib/neeto_translate_cli/api.rb
42
42
  - lib/neeto_translate_cli/cli.rb
43
+ - lib/neeto_translate_cli/next_i18next/payload_builder.rb
43
44
  - lib/neeto_translate_cli/payload_builder.rb
44
45
  - lib/neeto_translate_cli/translator.rb
45
46
  - lib/neeto_translate_cli/version.rb