lingua_rs 0.5.0 → 0.6.1

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: 9ec0e0ba5844b9b3e47cd60babbc90ac03791bc83e3327e78b7f2d83ba4a71d8
4
- data.tar.gz: 55af5915e63a1b34cbc5c73d2e2c63b6a1ce2030183112c54aad888b299bc889
3
+ metadata.gz: 94314611395fba47d42021ab91fc1f0db7b7f5311a64796a8c98b36372c5b2b0
4
+ data.tar.gz: c627fa1a1510945411506662fb22907546f4a5916352680aa09e86f5f93f9d33
5
5
  SHA512:
6
- metadata.gz: b6bfc5d1605bf171e7be4dd899e7b82460f4c8b81ab541ff97a18fb59205a752e9cfe12de640c20b6a60a4814bc8e89e884b9d501a2ec3b5a4e4f0b4bc2e094d
7
- data.tar.gz: ecf2866f980b9ddd7189d639ea1330a4f47f8f0a528dcb636358c7c6de30add2d8a854cee8252eac36540fc528b1836eedebbd03313eeb1de167cd18c241afbf
6
+ metadata.gz: 202e31c4f0775dfd7f9976720efcde6c0d7af4a3169771d3690f01f5b960a55406e697a06ecf6c48a682ad39f264ccfec2b2dc14bdc7d5a3fc0fcfd5d966c06a
7
+ data.tar.gz: 618a2269f52c7dd1a0999f93f13e7a58b02aa6e2a584a161e89c914166b7299dd03ef3b2401599997ef91d58ef7c2586daca2968bf125efc0edbf4bd62efb51c
data/README.md CHANGED
@@ -25,7 +25,7 @@ Then run `bundle install`.
25
25
 
26
26
  ### Build requirements
27
27
 
28
- A Rust toolchain is required to compile the native extension.
28
+ A Rust toolchain (**1.87+**) is required to compile the native extension.
29
29
 
30
30
  ## Usage
31
31
 
@@ -157,9 +157,18 @@ detector.detect_multiple_batch(['Bonjour le monde. Hello world.', 'Ich bin müde
157
157
  | Method | Return type | Description |
158
158
  |---|---|---|
159
159
  | `detect_batch(texts)` | `Array<Language\|nil>` | Detect language of each text |
160
- | `detect_multiple_batch(texts)` | `Array<Array<Segment>>` | Mixed-language detection for each text |
161
- | `confidence_values_batch(texts)` | `Array<Array<ConfidenceResult>>` | Confidence values for each text |
162
160
  | `confidence_batch(texts, language)` | `Array<Float>` | Confidence for a specific language across texts |
161
+ | `confidence_values_batch(texts)` | `Array<Array<ConfidenceResult>>` | Confidence values for each text |
162
+ | `detect_multiple_batch(texts)` | `Array<Array<Segment>>` | Mixed-language detection for each text |
163
+
164
+ Results are returned in the same order as the input, so you can pair them with `zip`:
165
+
166
+ ```ruby
167
+ texts = ['Bonjour le monde', 'Hello world', 'Hallo Welt']
168
+ texts.zip(detector.detect_batch(texts)) do |text, language|
169
+ puts "#{text} => #{language}"
170
+ end
171
+ ```
163
172
 
164
173
  ### Error handling
165
174
 
@@ -231,6 +240,49 @@ Returned by `detect_multiple`.
231
240
  | `to_s` | `String` | `'French (0-22): Parlez-vous français? '` |
232
241
  | `inspect` | `String` | `'#<Lingua::Segment French (0-22) "Parlez-vous français? ">'` |
233
242
 
243
+ ## Command-line tool
244
+
245
+ The gem ships with a `lingua` executable that wraps the library for shell use.
246
+
247
+ ```bash
248
+ # Text as argument or on stdin
249
+ lingua 'Bonjour le monde' # => French
250
+ echo 'Hello world' | lingua # => English
251
+
252
+ # Output format
253
+ lingua -f iso 'Bonjour le monde' # => fr
254
+ lingua -f iso6393 'Bonjour le monde' # => fra
255
+ lingua -f json 'Bonjour le monde' # => {"name":"French","iso":"fr","iso6393":"fra"}
256
+
257
+ # Confidence values
258
+ lingua -c -l en,fr,de 'Bonjour le monde'
259
+ # French: 0.8217
260
+ # German: 0.1216
261
+ # English: 0.0567
262
+
263
+ # Mixed-language detection
264
+ lingua -m -l en,fr,de 'Parlez-vous français? Hello world.'
265
+ # French (0-22): Parlez-vous français?
266
+ # English (22-34): Hello world.
267
+
268
+ # Restrict candidates
269
+ lingua -l en,fr,de 'Bonjour'
270
+
271
+ # Batch: one text per line (use "-" for stdin)
272
+ lingua --batch texts.txt
273
+ cat texts.txt | lingua --batch -
274
+ ```
275
+
276
+ | Option | Description |
277
+ |---|---|
278
+ | `-f`, `--format FORMAT` | Output format: `name` (default), `iso`, `iso6393`, `json` |
279
+ | `-c`, `--confidences` | Output confidence for all candidate languages |
280
+ | `-m`, `--multiple` | Detect multiple languages within the text |
281
+ | `-l`, `--languages LIST` | Comma-separated list of languages (names or ISO codes) |
282
+ | `--batch FILE` | Treat each line of FILE (or `-` for stdin) as a separate input |
283
+ | `-v`, `--version` | Show version |
284
+ | `-h`, `--help` | Show help |
285
+
234
286
  ## Optimization: selecting languages
235
287
 
236
288
  By default, all 75 languages are compiled into the native extension (~278 MB). If you only need a subset, select languages at build time to reduce binary size and improve detection speed.
data/exe/lingua ADDED
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'optparse'
5
+ require 'json'
6
+ require 'lingua'
7
+
8
+ def build_parser(options)
9
+ OptionParser.new do |opts|
10
+ opts.banner = 'Usage: lingua [options] [TEXT]'
11
+ opts.separator ''
12
+ opts.separator 'If TEXT is omitted, input is read from stdin.'
13
+ opts.separator ''
14
+ opts.separator 'Options:'
15
+
16
+ opts.on('-f', '--format FORMAT', %w[iso iso6393 name json],
17
+ 'Output format: name (default), iso, iso6393, json') { |f| options[:format] = f.to_sym }
18
+ opts.on('-c', '--confidences',
19
+ 'Output confidence values for all candidate languages') { options[:mode] = :confidences }
20
+ opts.on('-m', '--multiple',
21
+ 'Detect multiple languages within the text') { options[:mode] = :multiple }
22
+ opts.on('-l', '--languages LIST',
23
+ 'Restrict detection to comma-separated languages (names or ISO codes)') do |list|
24
+ options[:languages] = list.split(',').map(&:strip)
25
+ end
26
+ opts.on('--batch FILE',
27
+ 'Treat each line of FILE (or "-" for stdin) as a separate input') { |f| options[:batch] = f }
28
+ opts.on('-h', '--help', 'Show this help') do
29
+ puts opts
30
+ exit
31
+ end
32
+ opts.on('-v', '--version', 'Show version') do
33
+ puts Lingua::VERSION
34
+ exit
35
+ end
36
+ end
37
+ end
38
+
39
+ options = { format: :name, mode: :detect, languages: nil, batch: nil }
40
+ build_parser(options).parse!
41
+
42
+ def format_language(lang, format)
43
+ return nil if lang.nil?
44
+
45
+ case format
46
+ when :iso then lang.to_iso
47
+ when :iso6393 then lang.to_iso6393
48
+ when :name then lang.name
49
+ when :json then { name: lang.name, iso: lang.to_iso, iso6393: lang.to_iso6393 }
50
+ end
51
+ end
52
+
53
+ def render_detect(lang, format)
54
+ formatted = format_language(lang, format)
55
+ if format == :json
56
+ JSON.generate(formatted)
57
+ else
58
+ formatted.to_s
59
+ end
60
+ end
61
+
62
+ def render_confidences(results, format)
63
+ if format == :json
64
+ JSON.generate(results.map do |r|
65
+ { language: format_language(r.language, :iso), confidence: r.confidence }
66
+ end)
67
+ else
68
+ results.map { |r| "#{format_language(r.language, format)}: #{format('%.4f', r.confidence)}" }
69
+ .join("\n")
70
+ end
71
+ end
72
+
73
+ def render_multiple(segments, format)
74
+ if format == :json
75
+ JSON.generate(segments.map do |s|
76
+ { language: format_language(s.language, :iso),
77
+ start_index: s.start_index,
78
+ end_index: s.end_index,
79
+ text: s.text }
80
+ end)
81
+ else
82
+ segments.map do |s|
83
+ "#{format_language(s.language, format)} (#{s.start_index}-#{s.end_index}): #{s.text}"
84
+ end.join("\n")
85
+ end
86
+ end
87
+
88
+ def process(text, detector, options)
89
+ case options[:mode]
90
+ when :detect
91
+ render_detect(detector.detect(text), options[:format])
92
+ when :confidences
93
+ render_confidences(detector.confidence_values(text), options[:format])
94
+ when :multiple
95
+ render_multiple(detector.detect_multiple(text), options[:format])
96
+ end
97
+ end
98
+
99
+ begin
100
+ detector_options = {}
101
+ detector_options[:languages] = options[:languages] if options[:languages]
102
+ detector = Lingua::Detector.new(**detector_options)
103
+
104
+ if options[:batch]
105
+ io = options[:batch] == '-' ? $stdin : File.open(options[:batch], 'r')
106
+ io.each_line do |line|
107
+ line = line.chomp
108
+ next if line.empty?
109
+
110
+ puts process(line, detector, options)
111
+ end
112
+ io.close unless io == $stdin
113
+ else
114
+ text = ARGV.empty? ? $stdin.read : ARGV.join(' ')
115
+ text = text.strip
116
+ if text.empty?
117
+ warn 'lingua: no input text'
118
+ exit 1
119
+ end
120
+ puts process(text, detector, options)
121
+ end
122
+ rescue Lingua::UnknownLanguageError => e
123
+ warn "lingua: #{e.message}"
124
+ exit 1
125
+ end
@@ -11,6 +11,12 @@ selection = with_config('lingua-languages', nil) || ENV.fetch('LINGUA_LANGUAGES'
11
11
  languages = selection.to_s.split(',').map { |lang| lang.strip.downcase }.reject(&:empty?)
12
12
 
13
13
  create_rust_makefile('lingua/lingua') do |r|
14
+ # Cargo strips debuginfo from release builds by default. With rustc <= 1.98.0,
15
+ # stripping leaves the LINKEDIT string pool misaligned and dyld on macOS 27+
16
+ # refuses to load the bundle ("mis-aligned LINKEDIT string pool"), see
17
+ # rust-lang/rust#157750. Can be removed once rustc >= 1.98.1 is the minimum.
18
+ r.extra_rustflags << '-Cstrip=none' if RUBY_PLATFORM.include?('darwin')
19
+
14
20
  unless languages.empty?
15
21
  r.extra_cargo_args << '--no-default-features'
16
22
  r.features = languages
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lingua
4
- VERSION = '0.5.0'
4
+ VERSION = '0.6.1'
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lingua_rs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sébastien Vrillaud
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-04-08 00:00:00.000000000 Z
10
+ date: 2026-10-03 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rb_sys
@@ -42,7 +42,8 @@ description: Native Ruby bindings for the Lingua Rust library, bringing highly a
42
42
  scores and ISO 639-1/639-3 language codes.
43
43
  email:
44
44
  - kochka@gmail.com
45
- executables: []
45
+ executables:
46
+ - lingua
46
47
  extensions:
47
48
  - ext/lingua/extconf.rb
48
49
  extra_rdoc_files: []
@@ -50,6 +51,7 @@ files:
50
51
  - LICENSE.txt
51
52
  - README.md
52
53
  - Rakefile
54
+ - exe/lingua
53
55
  - ext/lingua/Cargo.toml
54
56
  - ext/lingua/extconf.rb
55
57
  - ext/lingua/src/confidence_result.rs
@@ -84,7 +86,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
84
86
  - !ruby/object:Gem::Version
85
87
  version: '0'
86
88
  requirements: []
87
- rubygems_version: 4.0.9
89
+ rubygems_version: 4.0.10
88
90
  specification_version: 4
89
91
  summary: High-accuracy language detection powered by Lingua (Rust).
90
92
  test_files: []