whatlanguage 1.0.6 → 2.0.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
- SHA1:
3
- metadata.gz: ccd0489249d639e17bda9ae90c496d33e2e6048a
4
- data.tar.gz: 83a969f3f186de199996e19bd6c6f391ba7cae24
2
+ SHA256:
3
+ metadata.gz: 53fea55810c7a8eb102970d6d8c3fe039b031680ff0f23eb6a1c7fec6ad1a602
4
+ data.tar.gz: f960efb55e0d04b5e457ef53f6c382434a334eea9d44fab2065e7ce9d4376747
5
5
  SHA512:
6
- metadata.gz: a1fbd9f4745e74637c8eddf8a0c4ac74fed02493d00b011c8e3de80887000253b0d6e39260d54afed9cc1918270c3dad227c963c07591840ad4692ecd775682a
7
- data.tar.gz: 59a45845d1f19f073d0f1af57526fcedea5813126f93a7795fe4218842bcf6212d7169f6a34d04d060d587f24c172558c7548ae7d063345f7e5a4800c105f078
6
+ metadata.gz: 99e1be592f692ba51e3a973a489703f955238da71985feb91b424e9203b8ae29d1ff635d5479ee6cea0226a06cd74c10c4f859a722c76914f277df3d41c3c779
7
+ data.tar.gz: e13bf56aa67c969d86213e9f1bd34bb2f0aa4ab0ab5db4c1b735ef84c9c3d2ad8e7891f0104a0881833fb5f54c42235132cf48f7a75af38f1cf5f71280529a31
data/CHANGELOG.md ADDED
@@ -0,0 +1,47 @@
1
+ # Changelog
2
+
3
+ ## 2.0.1 / 2026-07-11
4
+
5
+ - Added a `whatlanguage` command-line executable that reads from files given as
6
+ arguments (or stdin) and prints the ISO 639 code of the detected language, or
7
+ `und` if undetermined. (#50, suggested by Keith Bennett)
8
+
9
+ ## 2.0.0 / 2026-06-10
10
+
11
+ - Rewrote the detection engine from scratch. Bloom-filter dictionary lookups are
12
+ replaced by a script router plus character-trigram out-of-place scoring (a pure-Ruby
13
+ port of whatlang/Franc, public-domain UDHR-derived profiles).
14
+ - Expanded from 20 to 160+ languages across 20+ scripts.
15
+ - Removed the ~5 MB of binary `.lang` filter files and the wordlist corpus; the model
16
+ is now a single ~220 KB JSON file. No dependencies beyond the standard library.
17
+ - Requires Ruby 3.0 or newer.
18
+ - Added `#detect`, `#ranked`, and `#score_hash` for callers that need result metadata
19
+ or runner-up scores. `#scores` and `#process_text` remain as compatibility aliases.
20
+ - Added class-level convenience methods: `WhatLanguage.detect`, `.language`,
21
+ `.language_iso`, `.ranked`, `.score_hash`, and `.languages`.
22
+ - Added `only:` for configured detectors, replacing positional language
23
+ selection as the documented API.
24
+ - Removed the `String#language` and `String#language_iso` monkeypatch.
25
+ - Short shared-script fragments now return `nil` by default; pass `min_chars: 0`
26
+ to preserve the previous best-effort behavior.
27
+ - Removed internals: `BloominSimple`, `BitField`, the filter-build scripts.
28
+
29
+ ## 1.0.6 / 2016-01-28
30
+
31
+ - Minor test fixes and tweaks
32
+ - New release taking into account a handful of pull requests
33
+
34
+ ## 1.0.5 / 2013-10-05
35
+
36
+ - Many more languages supported
37
+
38
+ ## 1.0.4 / 2013-03-07
39
+
40
+ ## 1.0.1 / 2008-08-22
41
+
42
+ - Public release
43
+ - Removed wordlists from distribution to reduce size
44
+
45
+ ## 1.0.0 / 2007-07-02
46
+
47
+ - First version with pre-built English, French, and Spanish filters
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source 'https://rubygems.org'
1
+ # frozen_string_literal: true
2
2
 
3
- # Specify your gem's dependencies in whatlanguage2.gemspec
3
+ source 'https://rubygems.org'
4
4
  gemspec
data/LICENSE.txt CHANGED
@@ -1,10 +1,43 @@
1
- Copyright (c) 2008-2013 Peter Cooper
2
-
3
1
  MIT License
4
2
 
3
+ Ruby code is Copyright (c) 2007-2026 Peter Cooper
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ ---
25
+
26
+ lib/whatlanguage/trigrams.json is licensed as per the https://github.com/greyblake/whatlang-rs project.
27
+
28
+ Its license is as follows:
29
+
30
+ (The MIT License)
31
+
32
+ Copyright (c) 2017 Sergey Potapov <blake131313@gmail.com>
33
+ Copyright (c) 2014 Titus Wormer <tituswormer@gmail.com>
34
+ Copyright (c) 2008 Kent S Johnson
35
+ Copyright (c) 2006 Jacob R Rideout <kde@jacobrideout.net>
36
+ Copyright (c) 2004 Maciej Ceglowski
37
+
5
38
  Permission is hereby granted, free of charge, to any person obtaining
6
39
  a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
40
+ 'Software'), to deal in the Software without restriction, including
8
41
  without limitation the rights to use, copy, modify, merge, publish,
9
42
  distribute, sublicense, and/or sell copies of the Software, and to
10
43
  permit persons to whom the Software is furnished to do so, subject to
@@ -13,10 +46,10 @@ the following conditions:
13
46
  The above copyright notice and this permission notice shall be
14
47
  included in all copies or substantial portions of the Software.
15
48
 
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
49
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
50
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
51
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
52
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
53
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
54
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
55
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,114 +1,85 @@
1
1
  # whatlanguage
2
2
 
3
- by Peter Cooper
3
+ Pure Ruby natural language detection for 160+ languages.
4
4
 
5
- Text language detection. Quick, fast, memory efficient, and all in pure Ruby. Uses Bloom filters for aforementioned speed and memory benefits. It works well on texts of over 10 words in length (e.g. blog posts or comments) and *very poorly* on short or Twitter-esque text, so be aware.
6
-
7
- Works with Dutch, English, Farsi, French, German, Italian, Pinyin, Swedish, Portuguese, Russian, Arabic, Finnish, Greek, Hebrew, Hungarian, Korean, Norwegian, Polish and Spanish out of the box.
5
+ ```ruby
6
+ require 'whatlanguage'
8
7
 
9
- ## Important note
8
+ WhatLanguage.language("Que linguagem é essa? É uma pergunta sobre a língua portuguesa.")
9
+ # => :portuguese
10
+ ```
10
11
 
11
- This library was first built in 2007 and has received only a few minor updates over the years. There are now more efficient and effective algorithms for doing language detection which I am investigating for a future WhatLanguage.
12
+ - `gem install whatlanguage`
13
+ - No runtime dependencies.
14
+ - Supports 20+ writing systems.
15
+ - Ships a compact ~220 KB trigram model.
16
+ - Requires Ruby 3.0+ (JRuby and TruffleRuby also good)
17
+ - **Best on sentence-length text or longer.** Short texts can have ambiguous results.
12
18
 
13
- This library has been updated to be distributed and to work on modern Ruby implementations but other than that, has had no significant improvements.
19
+ > [!IMPORTANT]
20
+ > v2.0 has many breaking changes as the entire library has been reimplemented, though the core `WhatLanguage.language` API remains similar. Versions 1.0.6 and earlier (so the 2007-2025 run of the library) used a Bloom-filter technique and had 5MB of binary files to handle ~20 languages. Version 2.0 is more accurate, faster, and supports more languages from a single 220KB JSON file :-)
14
21
 
15
- ## Synopsis
22
+ ## How it works
16
23
 
17
- Full Example
24
+ Detection is in two stages. First, the dominant Unicode script is detected; scripts used by a single language (Greek, Korean, Thai, Japanese using Hiragana/Katakana) resolve immediately. For scripts shared by several languages (e.g. Latin, Cyrillic, Arabic, Hebrew) trigrams are ranked by frequency and compared against candidate language profiles.
18
25
 
19
- ```ruby
20
- require 'whatlanguage/string'
21
-
22
- texts = []
23
- texts << %q{Deux autres personnes ont été arrêtées durant la nuit}
24
- texts << %q{The links between the attempted car bombings in Glasgow and London are becoming clearer}
25
- texts << %q{En estado de máxima alertaen su nivel de crítico}
26
- texts << %q{Returns the object in enum with the maximum value.}
27
- texts << %q{Propose des données au sujet de la langue espagnole.}
28
- texts << %q{La palabra "mezquita" se usa en español para referirse a todo tipo de edificios dedicados.}
29
- texts << %q{اللغة التي هي هذه؟}
30
- texts << %q{Mitä kieltä tämä on?}
31
- texts << %q{Ποια γλώσσα είναι αυτή;}
32
- texts << %q{באיזו שפה זה?}
33
- texts << %q{Milyen nyelv ez?}
34
- texts << %q{이 어떤 언어인가?}
35
- texts << %q{Hvilket språk er dette?}
36
- texts << %q{W jakim języku to jest?}
37
-
38
- texts.each { |text| puts "#{text[0..18]}... is in #{text.language.to_s.capitalize}" }
39
- ```
26
+ The trigram profiles are vendored from [whatlang](https://github.com/greyblake/whatlang-rs), a port of [Franc](https://github.com/wooorm/franc), whose models are built from the public-domain UDHR corpus (see Credits). The model is a ~220 KB JSON file.
40
27
 
41
- Initialize WhatLanguage with all filters
42
28
 
43
- ```ruby
44
- wl = WhatLanguage.new(:all)
45
- ```
29
+ ## Usage
46
30
 
47
- Return language with best score
31
+ Return a full detection result:
48
32
 
49
33
  ```ruby
50
- wl.language(text)
34
+ wl = WhatLanguage.new
35
+ text = "Die Stadt plant neue Investitionen in den öffentlichen Verkehr"
36
+ result = wl.detect(text)
37
+ result.language # => :german
38
+ result.iso # => :de
39
+ result.score # => 79018
40
+ result.ranked # => [[:german, 79018], [:dutch, 77631], ... ]
51
41
  ```
52
42
 
53
- Return hash with scores for all relevant languages
43
+ Return ranked scores, or the raw score hash:
54
44
 
55
45
  ```ruby
56
- wl.process_text(text)
46
+ wl.ranked(text) # => [[:german, 79018], [:dutch, 77631], ... ]
47
+ wl.score_hash(text) # => { german: 79018, dutch: 77631, ... }
57
48
  ```
58
49
 
59
- Convenience methods on String
50
+ Restrict candidate languages:
60
51
 
61
52
  ```ruby
62
- "This is a test".language # => :english
63
- "This is a test".language_iso # => :en
53
+ wl = WhatLanguage.new(only: [:english, :german, :french])
64
54
  ```
65
55
 
66
- Initialize WhatLanguage with certain languages
56
+ Short Latin-script fragments are ignored by default because there is not enough signal to rank shared-script languages reliably. The threshold applies to the statistical trigram stage; scripts that identify a single supported language, such as Greek, Korean, or Thai, can still resolve from shorter text. The threshold can be adjusted:
67
57
 
68
58
  ```ruby
69
- wl = WhatLanguage.new(:english, :german, :french)
59
+ wl = WhatLanguage.new(min_chars: 0)
70
60
  ```
71
61
 
72
- ## Requirements
62
+ ## Command line
73
63
 
74
- None, minor libraries (BloominSimple and BitField) included with this release.
64
+ Installing the gem also installs a `whatlanguage` executable that reads from files given as arguments (or stdin) and prints the ISO 639 code of the detected language, or `und` if undetermined:
75
65
 
76
- ## Installation
77
-
78
- gem install whatlanguage
79
-
80
- To test, go into irb, then:
81
-
82
- ```ruby
83
- require 'whatlanguage'
84
- "Je suis un homme".language
66
+ ```bash
67
+ $ whatlanguage README.md
68
+ en
69
+ $ echo "Wie geht es dir heute?" | whatlanguage
70
+ de
85
71
  ```
86
72
 
87
- ## Credits
88
-
89
- Contributions from Konrad Reiche, Salimane Adjao Moustapha, and others appreciated.
90
-
91
- ## License
92
-
93
- MIT License
73
+ ## Known limitations
94
74
 
95
- Copyright (c) 2007-2016 Peter Cooper
75
+ - Short fragments are unreliable. For languages resolved by statistical comparison, fewer than 10 significant characters returns `nil` by default. **This is the biggest thing I want to fix.** I think there should be a mechanism for "weighting" languages so that less likely languages don't frequently appear for small English samples, say.
76
+ - Scores are relative ranking values, not probabilities. Use `#ranked` or `#detect.ranked` when close runners-up matter.
77
+ - Closely related written languages can be hard to separate, especially Norwegian Bokmål/Danish, Hebrew/Yiddish, and similar language pairs.
78
+ - Kanji-only Japanese text can classify as Chinese because Han characters alone do not identify the language.
79
+ - Romanized text is classified by Latin-script trigram profiles; it is not treated as native-script text.
96
80
 
97
- Permission is hereby granted, free of charge, to any person obtaining
98
- a copy of this software and associated documentation files (the
99
- 'Software'), to deal in the Software without restriction, including
100
- without limitation the rights to use, copy, modify, merge, publish,
101
- distribute, sublicense, and/or sell copies of the Software, and to
102
- permit persons to whom the Software is furnished to do so, subject to
103
- the following conditions:
81
+ ## Credits
104
82
 
105
- The above copyright notice and this permission notice shall be
106
- included in all copies or substantial portions of the Software.
83
+ Contributions from Konrad Reiche, Salimane Adjao Moustapha, Andrew Cone, Lasse Skindstad Ebert, Henrik Nyh, Daniel Sandbecker, Michael Hartl, Pedro Lambert, Tobias Preuss, Pepijn Looije, Keith Bennett, and others appreciated.
107
84
 
108
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
109
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
110
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
111
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
112
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
113
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
114
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
85
+ The trigram language profiles in `lib/whatlanguage/trigrams.json` are taken from [whatlang](https://github.com/greyblake/whatlang-rs) (MIT, © Sergey Potapov), itself a derivative of [Franc](https://github.com/wooorm/franc) (MIT, © Titus Wormer). Those profiles are derived from the public-domain Universal Declaration of Human Rights translations.
data/Rakefile CHANGED
@@ -1,6 +1,12 @@
1
- require "bundler/gem_tasks"
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
2
4
  require 'rake/testtask'
3
5
 
4
- Rake::TestTask.new
6
+ Rake::TestTask.new do |t|
7
+ t.libs << 'lib' << 'test'
8
+ t.pattern = 'test/**/*_test.rb'
9
+ t.warning = false
10
+ end
5
11
 
6
- task :default => :test
12
+ task default: :test
data/exe/whatlanguage ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'whatlanguage'
5
+
6
+ # Reads from files given as arguments, or stdin otherwise. Prints the ISO 639
7
+ # code of the detected language, or "und" (undetermined) if detection fails.
8
+ puts WhatLanguage.language_iso(ARGF.read) || 'und'
@@ -0,0 +1,180 @@
1
+ # frozen_string_literal: true
2
+
3
+ # AUTO-GENERATED from the ISO 639-3 registry + whatlang dataset codes.
4
+ # Maps ISO 639-3 code => [language name symbol, ISO 639-1 (or 639-3 fallback) symbol].
5
+ # Original gem languages keep their historical symbols and 2-letter codes.
6
+ class WhatLanguage
7
+ CODE_INFO = {
8
+ "ace" => [:achinese, :ace],
9
+ "ada" => [:adangme, :ada],
10
+ "afr" => [:afrikaans, :af],
11
+ "aka" => [:akan, :ak],
12
+ "amh" => [:amharic, :am],
13
+ "ara" => [:arabic, :ar],
14
+ "hye" => [:armenian, :hy],
15
+ "quy" => [:ayacucho_quechua, :quy],
16
+ "aze" => [:azerbaijani, :az],
17
+ "ban" => [:balinese, :ban],
18
+ "rmn" => [:balkan_romani, :rmn],
19
+ "bam" => [:bambara, :bm],
20
+ "bci" => [:baoule, :bci],
21
+ "bel" => [:belarusian, :be],
22
+ "bem" => [:bemba, :bem],
23
+ "ben" => [:bengali, :bn],
24
+ "bho" => [:bhojpuri, :bho],
25
+ "bin" => [:bini, :bin],
26
+ "bos" => [:bosnian, :bs],
27
+ "bug" => [:buginese, :bug],
28
+ "bul" => [:bulgarian, :bg],
29
+ "mya" => [:burmese, :my],
30
+ "cat" => [:catalan, :ca],
31
+ "ceb" => [:cebuano, :ceb],
32
+ "tzm" => [:central_atlas_tamazight, :tzm],
33
+ "ayr" => [:central_aymara, :ayr],
34
+ "bcl" => [:central_bikol, :bcl],
35
+ "knc" => [:central_kanuri, :knc],
36
+ "nhn" => [:central_nahuatl, :nhn],
37
+ "nya" => [:chichewa, :ny],
38
+ "qug" => [:chimborazo_highland_quichua, :qug],
39
+ "cmn" => [:chinese, :zh],
40
+ "cjk" => [:chokwe, :cjk],
41
+ "hrv" => [:croatian, :hr],
42
+ "quz" => [:cusco_quechua, :quz],
43
+ "ces" => [:czech, :cs],
44
+ "dan" => [:danish, :da],
45
+ "nld" => [:dutch, :nl],
46
+ "dyu" => [:dyula, :dyu],
47
+ "emk" => [:eastern_maninkakan, :emk],
48
+ "eng" => [:english, :en],
49
+ "epo" => [:esperanto, :eo],
50
+ "est" => [:estonian, :et],
51
+ "ewe" => [:ewe, :ee],
52
+ "pes" => [:farsi, :fa],
53
+ "fin" => [:finnish, :fi],
54
+ "fon" => [:fon, :fon],
55
+ "fra" => [:french, :fr],
56
+ "gaa" => [:ga, :gaa],
57
+ "glg" => [:galician, :gl],
58
+ "lug" => [:ganda, :lg],
59
+ "kat" => [:georgian, :ka],
60
+ "deu" => [:german, :de],
61
+ "ell" => [:greek, :el],
62
+ "guj" => [:gujarati, :gu],
63
+ "hat" => [:haitian, :ht],
64
+ "khk" => [:halh_mongolian, :khk],
65
+ "hau" => [:hausa, :ha],
66
+ "heb" => [:hebrew, :he],
67
+ "hil" => [:hiligaynon, :hil],
68
+ "hin" => [:hindi, :hi],
69
+ "hun" => [:hungarian, :hu],
70
+ "ibb" => [:ibibio, :ibb],
71
+ "ibo" => [:igbo, :ig],
72
+ "ilo" => [:iloko, :ilo],
73
+ "ind" => [:indonesian, :id],
74
+ "ita" => [:italian, :it],
75
+ "jpn" => [:japanese, :ja],
76
+ "jav" => [:javanese, :jv],
77
+ "kbp" => [:kabiye, :kbp],
78
+ "kan" => [:kannada, :kn],
79
+ "kaz" => [:kazakh, :kk],
80
+ "khm" => [:khmer, :km],
81
+ "kmb" => [:kimbundu, :kmb],
82
+ "kin" => [:kinyarwanda, :rw],
83
+ "kir" => [:kirghiz, :ky],
84
+ "koi" => [:komi_permyak, :koi],
85
+ "kng" => [:koongo, :kng],
86
+ "kor" => [:korean, :ko],
87
+ "kur" => [:kurdish, :ku],
88
+ "lat" => [:latin, :la],
89
+ "lav" => [:latvian, :lv],
90
+ "lin" => [:lingala, :ln],
91
+ "lit" => [:lithuanian, :lt],
92
+ "src" => [:logudorese_sardinian, :src],
93
+ "nds" => [:low_german, :nds],
94
+ "lua" => [:luba_lulua, :lua],
95
+ "lun" => [:lunda, :lun],
96
+ "mkd" => [:macedonian, :mk],
97
+ "mad" => [:madurese, :mad],
98
+ "mag" => [:magahi, :mag],
99
+ "mai" => [:maithili, :mai],
100
+ "vmw" => [:makhuwa, :vmw],
101
+ "kde" => [:makonde, :kde],
102
+ "mlg" => [:malagasy, :mg],
103
+ "mal" => [:malayalam, :ml],
104
+ "mar" => [:marathi, :mr],
105
+ "men" => [:mende, :men],
106
+ "min" => [:minangkabau, :min],
107
+ "mos" => [:mossi, :mos],
108
+ "ndo" => [:ndonga, :ng],
109
+ "nep" => [:nepali, :ne],
110
+ "dip" => [:northeastern_dinka, :dip],
111
+ "uzn" => [:northern_uzbek, :uzn],
112
+ "nob" => [:norwegian, :no],
113
+ "nno" => [:norwegian_nynorsk, :nn],
114
+ "nyn" => [:nyankole, :nyn],
115
+ "ori" => [:oriya, :or],
116
+ "orm" => [:oromo, :om],
117
+ "pam" => [:pampanga, :pam],
118
+ "pan" => [:panjabi, :pa],
119
+ "nso" => [:pedi, :nso],
120
+ "pol" => [:polish, :pl],
121
+ "por" => [:portuguese, :pt],
122
+ "ron" => [:romanian, :ro],
123
+ "run" => [:rundi, :rn],
124
+ "rus" => [:russian, :ru],
125
+ "sag" => [:sango, :sg],
126
+ "skr" => [:saraiki, :skr],
127
+ "srp" => [:serbian, :sr],
128
+ "sna" => [:shona, :sn],
129
+ "sin" => [:sinhala, :si],
130
+ "snn" => [:siona, :snn],
131
+ "slk" => [:slovak, :sk],
132
+ "slv" => [:slovenian, :sl],
133
+ "som" => [:somali, :so],
134
+ "snk" => [:soninke, :snk],
135
+ "hms" => [:southern_qiandong_miao, :hms],
136
+ "sot" => [:southern_sotho, :st],
137
+ "spa" => [:spanish, :es],
138
+ "suk" => [:sukuma, :suk],
139
+ "sun" => [:sundanese, :su],
140
+ "swh" => [:swahili, :swh],
141
+ "ssw" => [:swati, :ss],
142
+ "swe" => [:swedish, :sv],
143
+ "tgl" => [:tagalog, :tl],
144
+ "tgk" => [:tajik, :tg],
145
+ "tam" => [:tamil, :ta],
146
+ "tat" => [:tatar, :tt],
147
+ "tel" => [:telugu, :te],
148
+ "tha" => [:thai, :th],
149
+ "tir" => [:tigrinya, :ti],
150
+ "tem" => [:timne, :tem],
151
+ "tiv" => [:tiv, :tiv],
152
+ "tpi" => [:tok_pisin, :tpi],
153
+ "toi" => [:tonga, :toi],
154
+ "als" => [:tosk_albanian, :als],
155
+ "tso" => [:tsonga, :ts],
156
+ "tsn" => [:tswana, :tn],
157
+ "tur" => [:turkish, :tr],
158
+ "tuk" => [:turkmen, :tk],
159
+ "uig" => [:uighur, :ug],
160
+ "ukr" => [:ukrainian, :uk],
161
+ "umb" => [:umbundu, :umb],
162
+ "urd" => [:urdu, :ur],
163
+ "uzb" => [:uzbek, :uz],
164
+ "vie" => [:vietnamese, :vi],
165
+ "rmy" => [:vlax_romani, :rmy],
166
+ "war" => [:waray, :war],
167
+ "cym" => [:welsh, :cy],
168
+ "wol" => [:wolof, :wo],
169
+ "xho" => [:xhosa, :xh],
170
+ "yao" => [:yao, :yao],
171
+ "yid" => [:yiddish, :yi],
172
+ "yor" => [:yoruba, :yo],
173
+ "zul" => [:zulu, :zu],
174
+ }.freeze
175
+
176
+ # Convenience aliases for legacy selection symbols that no longer map 1:1.
177
+ NAME_ALIASES = { pinyin: :chinese, mandarin: :chinese }.freeze
178
+
179
+ private_constant :CODE_INFO, :NAME_ALIASES
180
+ end