i18n-context-generator 0.3.0 → 0.5.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 +4 -4
- data/README.md +163 -26
- data/lib/i18n_context_generator/android_resource.rb +209 -0
- data/lib/i18n_context_generator/apple_string_literal.rb +28 -0
- data/lib/i18n_context_generator/cache.rb +40 -8
- data/lib/i18n_context_generator/changed_location.rb +55 -0
- data/lib/i18n_context_generator/cli.rb +165 -73
- data/lib/i18n_context_generator/config/cli_values.rb +33 -0
- data/lib/i18n_context_generator/config/defaults.rb +35 -0
- data/lib/i18n_context_generator/config/schema.rb +225 -0
- data/lib/i18n_context_generator/config/serialization.rb +64 -0
- data/lib/i18n_context_generator/config/validation.rb +249 -0
- data/lib/i18n_context_generator/config.rb +315 -105
- data/lib/i18n_context_generator/context_extractor/cache_identity.rb +65 -0
- data/lib/i18n_context_generator/context_extractor/extraction_result.rb +46 -0
- data/lib/i18n_context_generator/context_extractor/run_logging.rb +65 -0
- data/lib/i18n_context_generator/context_extractor/source_entries.rb +103 -0
- data/lib/i18n_context_generator/context_extractor/source_filters.rb +104 -0
- data/lib/i18n_context_generator/context_extractor/translation_filters.rb +91 -0
- data/lib/i18n_context_generator/context_extractor/workflow.rb +118 -0
- data/lib/i18n_context_generator/context_extractor.rb +218 -164
- data/lib/i18n_context_generator/file_classifier.rb +72 -0
- data/lib/i18n_context_generator/generated_comment.rb +32 -0
- data/lib/i18n_context_generator/git_diff/xml_changes.rb +235 -0
- data/lib/i18n_context_generator/git_diff.rb +280 -88
- data/lib/i18n_context_generator/llm/anthropic.rb +65 -38
- data/lib/i18n_context_generator/llm/client.rb +294 -92
- data/lib/i18n_context_generator/llm/openai.rb +92 -51
- data/lib/i18n_context_generator/llm/openai_compatible.rb +20 -0
- data/lib/i18n_context_generator/llm/prompt_evidence.rb +47 -0
- data/lib/i18n_context_generator/llm/request_policy.rb +147 -0
- data/lib/i18n_context_generator/localization_syntax.rb +246 -0
- data/lib/i18n_context_generator/parsers/android_xml_parser.rb +47 -8
- data/lib/i18n_context_generator/parsers/base.rb +7 -4
- data/lib/i18n_context_generator/parsers/json_parser.rb +4 -0
- data/lib/i18n_context_generator/parsers/xcstrings_parser.rb +79 -0
- data/lib/i18n_context_generator/parsers/yaml_parser.rb +20 -7
- data/lib/i18n_context_generator/path_policy.rb +107 -0
- data/lib/i18n_context_generator/platform_validator.rb +24 -50
- data/lib/i18n_context_generator/run_metrics.rb +47 -0
- data/lib/i18n_context_generator/searcher/comment_masking.rb +115 -0
- data/lib/i18n_context_generator/searcher/match_filtering.rb +52 -0
- data/lib/i18n_context_generator/searcher/source_discovery.rb +232 -0
- data/lib/i18n_context_generator/searcher.rb +69 -201
- data/lib/i18n_context_generator/supplemental_context.rb +77 -0
- data/lib/i18n_context_generator/translation_comment_index.rb +121 -0
- data/lib/i18n_context_generator/version.rb +1 -1
- data/lib/i18n_context_generator/writers/android_xml_writer.rb +48 -18
- data/lib/i18n_context_generator/writers/atomic_file.rb +37 -0
- data/lib/i18n_context_generator/writers/csv_writer.rb +43 -18
- data/lib/i18n_context_generator/writers/helpers.rb +7 -29
- data/lib/i18n_context_generator/writers/json_writer.rb +31 -6
- data/lib/i18n_context_generator/writers/preview.rb +80 -0
- data/lib/i18n_context_generator/writers/result_serialization.rb +30 -0
- data/lib/i18n_context_generator/writers/strings_writer.rb +23 -12
- data/lib/i18n_context_generator/writers/swift_writer.rb +16 -54
- data/lib/i18n_context_generator/writers/xcstrings_writer.rb +57 -0
- data/lib/i18n_context_generator/xcstrings_document.rb +218 -0
- data/lib/i18n_context_generator/xml_scanner.rb +38 -0
- data/lib/i18n_context_generator.rb +20 -4
- metadata +62 -12
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module I18nContextGenerator
|
|
4
|
+
# A line in a Git diff, including the revision side needed by review clients.
|
|
5
|
+
#
|
|
6
|
+
# `fallback_line` identifies a corresponding line in the head revision. It is
|
|
7
|
+
# useful when a removed translator comment needs a right-side suggestion anchor.
|
|
8
|
+
ChangedLocation = Data.define(:file, :line, :side, :fallback_line) do
|
|
9
|
+
def initialize(file:, line:, side: :right, fallback_line: nil)
|
|
10
|
+
normalized_side = side.to_s.downcase.to_sym
|
|
11
|
+
raise ArgumentError, "Unsupported diff side: #{side}" unless %i[left right].include?(normalized_side)
|
|
12
|
+
|
|
13
|
+
super(
|
|
14
|
+
file: file.to_s,
|
|
15
|
+
line: Integer(line),
|
|
16
|
+
side: normalized_side,
|
|
17
|
+
fallback_line: fallback_line && Integer(fallback_line)
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.parse(value)
|
|
22
|
+
return value if value.is_a?(self)
|
|
23
|
+
|
|
24
|
+
match = /\A(.+):(\d+)\z/.match(value.to_s)
|
|
25
|
+
raise ArgumentError, "Invalid changed location: #{value.inspect}" unless match
|
|
26
|
+
|
|
27
|
+
new(file: match[1], line: match[2], side: :right)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def left?
|
|
31
|
+
side == :left
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def right?
|
|
35
|
+
side == :right
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def review_side
|
|
39
|
+
side.to_s.upcase
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def to_s
|
|
43
|
+
"#{file}:#{line}"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def to_h
|
|
47
|
+
{
|
|
48
|
+
file: file,
|
|
49
|
+
line: line,
|
|
50
|
+
side: side,
|
|
51
|
+
fallback_line: fallback_line
|
|
52
|
+
}
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -1,10 +1,39 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'thor'
|
|
4
|
+
require_relative 'config'
|
|
4
5
|
|
|
5
6
|
module I18nContextGenerator
|
|
7
|
+
# Configuration inspection commands kept separate from extraction options.
|
|
8
|
+
class ConfigCommand < Thor
|
|
9
|
+
def self.exit_on_failure?
|
|
10
|
+
true
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
desc 'validate [PATH]', 'Validate a client configuration file'
|
|
14
|
+
def validate(path = '.i18n-context-generator.yml')
|
|
15
|
+
Config.from_file(path).validate!
|
|
16
|
+
say "Configuration is valid (schema version #{Config::Schema::VERSION}): #{path}"
|
|
17
|
+
rescue I18nContextGenerator::Error => e
|
|
18
|
+
warn "Error: #{e.message}"
|
|
19
|
+
exit 1
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
6
23
|
# Thor-based CLI entry point for the i18n-context-generator command.
|
|
7
24
|
class CLI < Thor
|
|
25
|
+
register ConfigCommand, 'config', 'config SUBCOMMAND', 'Inspect or validate configuration'
|
|
26
|
+
|
|
27
|
+
def self.extraction_options
|
|
28
|
+
Config::Schema.cli_definitions.each do |definition|
|
|
29
|
+
option definition.cli_name, **definition.thor_options
|
|
30
|
+
end
|
|
31
|
+
option :translations, type: :string, hide: true,
|
|
32
|
+
desc: 'Deprecated: comma-separated translation files'
|
|
33
|
+
option :keys, type: :string, hide: true,
|
|
34
|
+
desc: 'Deprecated: comma-separated key filters'
|
|
35
|
+
end
|
|
36
|
+
|
|
8
37
|
def self.exit_on_failure?
|
|
9
38
|
true
|
|
10
39
|
end
|
|
@@ -28,49 +57,35 @@ module I18nContextGenerator
|
|
|
28
57
|
# Use config file
|
|
29
58
|
i18n-context-generator extract --config .i18n-context-generator.yml
|
|
30
59
|
DESC
|
|
31
|
-
|
|
32
|
-
option :translations, aliases: '-t', desc: 'Translation file(s), comma-separated'
|
|
33
|
-
option :source, aliases: '-s', desc: 'Source directory(ies) to search, comma-separated'
|
|
34
|
-
option :output, aliases: '-o', desc: 'Output file path (CSV written only if specified)'
|
|
35
|
-
option :format, aliases: '-f', enum: %w[csv json], desc: 'Output format (default: csv)'
|
|
36
|
-
option :provider, aliases: '-p', enum: %w[anthropic openai], desc: 'LLM provider (default: anthropic)'
|
|
37
|
-
option :model, aliases: '-m', desc: 'LLM model to use'
|
|
38
|
-
option :keys, aliases: '-k', desc: 'Filter keys (comma-separated patterns, supports * wildcard)'
|
|
39
|
-
option :concurrency, type: :numeric, desc: 'Number of concurrent requests (default: 5)'
|
|
40
|
-
option :dry_run, type: :boolean, desc: 'Show what would be processed without calling LLM'
|
|
41
|
-
option :cache, type: :boolean, desc: 'Enable caching of LLM results'
|
|
42
|
-
option :write_back, type: :boolean,
|
|
43
|
-
desc: 'Write context back to source translation files (.strings, strings.xml)'
|
|
44
|
-
option :write_back_to_code, type: :boolean,
|
|
45
|
-
desc: 'Write context back to Swift source code comment: parameters'
|
|
46
|
-
option :diff_base, type: :string, desc: 'Only process keys changed since this git ref (e.g., main, origin/main)'
|
|
47
|
-
option :context_prefix, type: :string,
|
|
48
|
-
desc: 'Prefix for context comments (default: "Context: ", use empty string for none)'
|
|
49
|
-
option :context_mode, type: :string, enum: %w[replace append],
|
|
50
|
-
desc: 'How to handle existing comments: replace or append (default: replace)'
|
|
51
|
-
option :start_key, type: :string, desc: 'Start processing from this key (inclusive)'
|
|
52
|
-
option :end_key, type: :string, desc: 'Stop processing at this key (inclusive)'
|
|
53
|
-
option :include_file_paths, type: :boolean,
|
|
54
|
-
desc: 'Include full source file paths in LLM prompts (default: false)'
|
|
55
|
-
option :include_translation_comments, type: :boolean,
|
|
56
|
-
desc: 'Include translation file comments in LLM prompts (default: true)'
|
|
57
|
-
option :redact_prompts, type: :boolean,
|
|
58
|
-
desc: 'Redact likely secrets and PII from LLM prompts (default: true)'
|
|
60
|
+
extraction_options
|
|
59
61
|
|
|
60
62
|
def extract
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
63
|
+
run_workflow(nil)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
desc 'check', 'Validate and check source usage without calling the LLM'
|
|
67
|
+
extraction_options
|
|
68
|
+
def check
|
|
69
|
+
run_workflow('check')
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
desc 'plan', 'Show selected keys and destinations without calling the LLM'
|
|
73
|
+
extraction_options
|
|
74
|
+
def plan
|
|
75
|
+
run_workflow('plan')
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
map 'preview-diff' => :preview_diff
|
|
79
|
+
desc 'preview-diff', 'Generate and preview write-back patches without modifying files'
|
|
80
|
+
extraction_options
|
|
81
|
+
def preview_diff
|
|
82
|
+
run_workflow('preview_diff')
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
desc 'apply', 'Generate context and apply the configured destinations'
|
|
86
|
+
extraction_options
|
|
87
|
+
def apply
|
|
88
|
+
run_workflow('apply')
|
|
74
89
|
end
|
|
75
90
|
|
|
76
91
|
desc 'init', 'Create a sample config file'
|
|
@@ -97,19 +112,52 @@ module I18nContextGenerator
|
|
|
97
112
|
|
|
98
113
|
private
|
|
99
114
|
|
|
115
|
+
def run_workflow(stage)
|
|
116
|
+
validate_options!
|
|
117
|
+
warn_deprecated_list_options!
|
|
118
|
+
config = Config.load(options)
|
|
119
|
+
config.merge_cli(workflow_stage: stage) if stage
|
|
120
|
+
config.validate!
|
|
121
|
+
if config.print_config
|
|
122
|
+
puts YAML.dump(config.to_h)
|
|
123
|
+
return
|
|
124
|
+
end
|
|
125
|
+
validate_destination!(config)
|
|
126
|
+
validate_api_key!(provider: config.provider, dry_run: config.dry_run) unless %w[check plan].include?(config.workflow_stage)
|
|
127
|
+
validate_diff_range!(base_ref: config.diff_base, head_ref: config.diff_head) if config.diff_base
|
|
128
|
+
extractor = ContextExtractor.new(config)
|
|
129
|
+
extractor.run
|
|
130
|
+
fail_if_extraction_errors!(extractor)
|
|
131
|
+
rescue I18nContextGenerator::Error => e
|
|
132
|
+
say_error "Error: #{e.message}"
|
|
133
|
+
exit 1
|
|
134
|
+
rescue Interrupt
|
|
135
|
+
say "\nInterrupted"
|
|
136
|
+
exit 130
|
|
137
|
+
end
|
|
138
|
+
|
|
100
139
|
def validate_options!
|
|
101
|
-
return if options[:
|
|
140
|
+
return if options[:print_config]
|
|
141
|
+
return if options[:config]
|
|
102
142
|
|
|
103
|
-
return if options[:translations]
|
|
143
|
+
return if options[:translation] || options[:translations]
|
|
144
|
+
return if options[:discovery_mode] == 'source' && options[:source]
|
|
104
145
|
|
|
105
|
-
say_error 'Error: --
|
|
146
|
+
say_error 'Error: --translation (-t) is required unless using a config file or --discovery-mode source with --source'
|
|
106
147
|
exit 1
|
|
107
148
|
end
|
|
108
149
|
|
|
150
|
+
def warn_deprecated_list_options!
|
|
151
|
+
say_error 'Warning: --translations is deprecated; repeat --translation instead.' if options[:translations]
|
|
152
|
+
say_error 'Warning: --keys is deprecated; repeat --key instead.' if options[:keys]
|
|
153
|
+
end
|
|
154
|
+
|
|
109
155
|
def validate_api_key!(provider: nil, dry_run: nil)
|
|
110
156
|
return if dry_run.nil? ? options[:dry_run] : dry_run
|
|
111
157
|
|
|
112
158
|
provider ||= options[:provider] || 'anthropic'
|
|
159
|
+
return if provider == 'openai_compatible'
|
|
160
|
+
|
|
113
161
|
env_var = case provider
|
|
114
162
|
when 'anthropic' then 'ANTHROPIC_API_KEY'
|
|
115
163
|
when 'openai' then 'OPENAI_API_KEY'
|
|
@@ -123,17 +171,30 @@ module I18nContextGenerator
|
|
|
123
171
|
exit 1
|
|
124
172
|
end
|
|
125
173
|
|
|
126
|
-
def
|
|
174
|
+
def validate_destination!(config)
|
|
175
|
+
return if %w[check plan].include?(config.workflow_stage)
|
|
176
|
+
return if config.dry_run
|
|
177
|
+
return if config.output_path || config.write_back || config.write_back_to_code
|
|
178
|
+
|
|
179
|
+
raise Error, 'A non-dry extraction requires --output, --write-back, or --write-back-to-code'
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def validate_diff_range!(base_ref: options[:diff_base], head_ref: options[:diff_head] || 'HEAD')
|
|
127
183
|
unless GitDiff.available?
|
|
128
184
|
say_error 'Error: --diff-base requires a git repository'
|
|
129
185
|
exit 1
|
|
130
186
|
end
|
|
131
187
|
|
|
132
|
-
git_diff = GitDiff.new(base_ref: base_ref)
|
|
133
|
-
|
|
188
|
+
git_diff = GitDiff.new(base_ref: base_ref, head_ref: head_ref)
|
|
189
|
+
unless git_diff.base_ref_exists?
|
|
190
|
+
say_error "Error: git ref '#{base_ref}' not found"
|
|
191
|
+
say_error 'Try: origin/main, main, or a specific commit SHA'
|
|
192
|
+
exit 1
|
|
193
|
+
end
|
|
194
|
+
return if git_diff.head_ref_exists?
|
|
134
195
|
|
|
135
|
-
say_error "Error: git ref '#{
|
|
136
|
-
say_error 'Try:
|
|
196
|
+
say_error "Error: git ref '#{head_ref}' not found"
|
|
197
|
+
say_error 'Try: HEAD, a branch name, or a specific commit SHA'
|
|
137
198
|
exit 1
|
|
138
199
|
end
|
|
139
200
|
|
|
@@ -149,12 +210,16 @@ module I18nContextGenerator
|
|
|
149
210
|
end
|
|
150
211
|
|
|
151
212
|
def sample_config
|
|
213
|
+
schema = Config::Schema
|
|
214
|
+
swift_functions = schema.default(:swift_functions).map { |function| " - #{function.inspect}" }.join("\n")
|
|
215
|
+
|
|
152
216
|
<<~YAML
|
|
153
217
|
# i18n-context-generator configuration
|
|
154
218
|
# Extract translation context from mobile app source code
|
|
219
|
+
schema_version: #{schema.default(:schema_version)}
|
|
155
220
|
|
|
156
221
|
# Translation files to process
|
|
157
|
-
# Supported formats: .strings (iOS), strings.xml (Android), .json, .yml
|
|
222
|
+
# Supported formats: .strings/.xcstrings (iOS), strings.xml (Android), .json, .yml
|
|
158
223
|
translations:
|
|
159
224
|
# iOS example
|
|
160
225
|
- path: ios/MyApp/Resources/Localizable.strings
|
|
@@ -162,61 +227,88 @@ module I18nContextGenerator
|
|
|
162
227
|
# Android example
|
|
163
228
|
# - path: android/app/src/main/res/values/strings.xml
|
|
164
229
|
|
|
230
|
+
# YAML locale roots are stripped only when configured explicitly
|
|
231
|
+
# - path: config/translations.yml
|
|
232
|
+
# locale: en
|
|
233
|
+
|
|
165
234
|
# Source code directories to search
|
|
166
235
|
source:
|
|
167
236
|
paths:
|
|
168
237
|
- ios/MyApp/
|
|
169
238
|
# - android/app/src/main/java/
|
|
239
|
+
# These entries extend the built-in dependency, build, and test ignores.
|
|
170
240
|
ignore:
|
|
171
|
-
- "**/Pods/**"
|
|
172
|
-
- "**/build/**"
|
|
173
241
|
- "**/*.generated.*"
|
|
174
|
-
|
|
242
|
+
|
|
243
|
+
# Optional free-form reference material included in every LLM request.
|
|
244
|
+
context:
|
|
245
|
+
files: []
|
|
246
|
+
# - GLOSSARY.md
|
|
247
|
+
# - docs/localization-style.md
|
|
175
248
|
|
|
176
249
|
# LLM configuration
|
|
177
250
|
llm:
|
|
178
|
-
provider:
|
|
179
|
-
model:
|
|
251
|
+
provider: #{schema.default(:provider)}
|
|
252
|
+
# model: provider-specific default
|
|
253
|
+
# For provider: openai_compatible, set an explicit model and endpoint.
|
|
254
|
+
# endpoint: http://127.0.0.1:11434/v1/responses
|
|
180
255
|
# API key is read from the matching provider env var
|
|
181
256
|
# (ANTHROPIC_API_KEY or OPENAI_API_KEY)
|
|
182
257
|
|
|
183
258
|
# Processing options
|
|
184
259
|
processing:
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
260
|
+
# Optional explicit platform override: ios or android
|
|
261
|
+
# platform: ios
|
|
262
|
+
# Discovery mode: auto, translations, or source
|
|
263
|
+
discovery_mode: #{schema.default(:discovery_mode)}
|
|
264
|
+
concurrency: #{schema.default(:concurrency)}
|
|
265
|
+
context_lines: #{schema.default(:context_lines)}
|
|
266
|
+
max_matches_per_key: #{schema.default(:max_matches_per_key)}
|
|
267
|
+
# Hard character limit for each prompt; oversized context is truncated
|
|
268
|
+
max_prompt_chars: #{schema.default(:max_prompt_chars)}
|
|
269
|
+
|
|
270
|
+
# Optional local cache. Only successful results are cached.
|
|
271
|
+
cache:
|
|
272
|
+
enabled: #{schema.default(:cache_enabled)}
|
|
273
|
+
directory: #{schema.default(:cache_dir)}
|
|
274
|
+
|
|
275
|
+
# Default workflow for programmatic/config-file runs.
|
|
276
|
+
workflow:
|
|
277
|
+
stage: #{schema.default(:workflow_stage)}
|
|
188
278
|
|
|
189
279
|
# Output configuration
|
|
190
280
|
output:
|
|
191
|
-
format:
|
|
281
|
+
format: #{schema.default(:output_format)}
|
|
192
282
|
path: translation-context.csv
|
|
193
|
-
#
|
|
194
|
-
|
|
283
|
+
# Write the selected CSV/JSON format to stdout instead of a file.
|
|
284
|
+
stdout: #{schema.default(:output_stdout)}
|
|
285
|
+
# Set to true to write context comments back to translation files
|
|
286
|
+
# (.strings, .xcstrings, strings.xml)
|
|
287
|
+
write_back: #{schema.default(:write_back)}
|
|
195
288
|
# Set to true to write context back to Swift source code comment: parameters
|
|
196
|
-
write_back_to_code:
|
|
289
|
+
write_back_to_code: #{schema.default(:write_back_to_code)}
|
|
197
290
|
# Prefix for context comments (use empty string for no prefix)
|
|
198
|
-
# context_prefix:
|
|
291
|
+
# context_prefix: #{schema.default(:context_prefix).inspect}
|
|
199
292
|
# How to handle existing comments: "replace" or "append"
|
|
200
|
-
# context_mode:
|
|
293
|
+
# context_mode: #{schema.default(:context_mode)}
|
|
201
294
|
|
|
202
|
-
# Swift-specific
|
|
295
|
+
# Swift-specific extraction and write-back configuration
|
|
203
296
|
swift:
|
|
204
|
-
#
|
|
297
|
+
# Custom entries extend the built-in localization functions (defaults shown)
|
|
205
298
|
functions:
|
|
206
|
-
|
|
207
|
-
- "String(localized:"
|
|
208
|
-
- "Text("
|
|
299
|
+
#{swift_functions}
|
|
209
300
|
# Add custom functions like:
|
|
210
301
|
# - "MyLocalizedString("
|
|
211
302
|
|
|
212
303
|
# Prompt privacy controls
|
|
213
304
|
privacy:
|
|
214
305
|
# Include full source paths in prompts sent to the LLM (default: false)
|
|
215
|
-
include_file_paths:
|
|
306
|
+
include_file_paths: #{schema.default(:include_file_paths)}
|
|
216
307
|
# Include translation file comments in prompts (default: true)
|
|
217
|
-
include_translation_comments:
|
|
218
|
-
#
|
|
219
|
-
|
|
308
|
+
include_translation_comments: #{schema.default(:include_translation_comments)}
|
|
309
|
+
# Best-effort redact likely secrets, URLs, and emails before sending prompts.
|
|
310
|
+
# Source snippets still leave the machine when using a remote provider.
|
|
311
|
+
redact_prompts: #{schema.default(:redact_prompts)}
|
|
220
312
|
YAML
|
|
221
313
|
end
|
|
222
314
|
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module I18nContextGenerator
|
|
4
|
+
class Config
|
|
5
|
+
# Normalizes repeatable singular CLI values while retaining explicit legacy
|
|
6
|
+
# comma-list support.
|
|
7
|
+
module CliValues
|
|
8
|
+
def cli_path_list(values, legacy: nil)
|
|
9
|
+
repeatable = Array(values).filter_map do |value|
|
|
10
|
+
normalized = value.to_s.strip
|
|
11
|
+
normalized unless normalized.empty?
|
|
12
|
+
end
|
|
13
|
+
(repeatable + split_legacy_list(legacy)).uniq
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def cli_key_filters(values, legacy: nil)
|
|
17
|
+
repeatable = Array(values).filter_map do |value|
|
|
18
|
+
normalized = value.to_s.strip
|
|
19
|
+
normalized unless normalized.empty?
|
|
20
|
+
end
|
|
21
|
+
repeatable + split_legacy_list(legacy)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def split_legacy_list(value)
|
|
27
|
+
Array(value).flat_map { |item| item.to_s.split(',') }
|
|
28
|
+
.map(&:strip)
|
|
29
|
+
.reject(&:empty?)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module I18nContextGenerator
|
|
4
|
+
class Config
|
|
5
|
+
# Built-in source exclusions and their additive merge policy.
|
|
6
|
+
module Defaults
|
|
7
|
+
def default_ignore_patterns
|
|
8
|
+
[
|
|
9
|
+
'**/node_modules/**',
|
|
10
|
+
'**/vendor/**',
|
|
11
|
+
'**/.git/**',
|
|
12
|
+
'**/build/**',
|
|
13
|
+
'**/dist/**',
|
|
14
|
+
'**/*.min.js',
|
|
15
|
+
'**/*.test.*',
|
|
16
|
+
'**/*.spec.*',
|
|
17
|
+
'**/Pods/**',
|
|
18
|
+
'**/Carthage/**',
|
|
19
|
+
'**/.build/**',
|
|
20
|
+
'**/DerivedData/**',
|
|
21
|
+
'**/*Tests.swift',
|
|
22
|
+
'**/*Tests.kt',
|
|
23
|
+
'**/*Test.java',
|
|
24
|
+
'**/*Test.kt'
|
|
25
|
+
]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def merge_ignore_patterns(patterns)
|
|
29
|
+
return patterns unless patterns.is_a?(Array)
|
|
30
|
+
|
|
31
|
+
(default_ignore_patterns + patterns).compact.uniq
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|