├── Gemfile ├── .travis.yml ├── lib ├── inflections │ ├── version.rb │ ├── nb.rb │ ├── tr.rb │ ├── kk.rb │ ├── es.rb │ ├── fr.rb │ ├── it.rb │ └── pt-BR.rb └── inflections.rb ├── test ├── test_helper.rb ├── tr_test.rb ├── nb_test.rb ├── it_test.rb ├── kk_test.rb ├── es_test.rb ├── pt-br_test.rb └── fr_test.rb ├── .gitignore ├── Rakefile ├── inflections.gemspec ├── LICENSE ├── CHANGELOG.markdown └── README.markdown /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # See http://about.travis-ci.org/docs/user/languages/ruby/ 2 | language: ruby 3 | rvm: 4 | - 2.0.0 5 | - 2.1.0 6 | - 2.2.5 7 | -------------------------------------------------------------------------------- /lib/inflections/version.rb: -------------------------------------------------------------------------------- 1 | module Inflections 2 | MAJOR = 4 3 | MINOR = 1 4 | PATCH = 0 5 | 6 | VERSION = [MAJOR, MINOR, PATCH].compact.join '.' 7 | end 8 | -------------------------------------------------------------------------------- /lib/inflections.rb: -------------------------------------------------------------------------------- 1 | require 'inflections/es' 2 | require 'inflections/fr' 3 | require 'inflections/kk' 4 | require 'inflections/nb' 5 | require 'inflections/tr' 6 | require 'inflections/pt-BR' 7 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path('../cases', __FILE__) 2 | 3 | require 'bundler/setup' 4 | require 'minitest/autorun' 5 | require 'minitest/pride' 6 | require 'active_support/inflector' 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | *.swp 19 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | 3 | require 'bundler/gem_tasks' 4 | require 'rake/testtask' 5 | 6 | task :default => :test 7 | 8 | Rake::TestTask.new(:test) do |t| 9 | t.libs << 'test' 10 | t.test_files = Dir.glob('test/*_test.rb') 11 | t.verbose = true 12 | end 13 | -------------------------------------------------------------------------------- /lib/inflections/nb.rb: -------------------------------------------------------------------------------- 1 | module Inflections 2 | ActiveSupport::Inflector.inflections(:nb) do |inflect| 3 | inflect.clear 4 | 5 | inflect.plural(/$/, 'er') 6 | inflect.plural(/r$/i, 're') 7 | inflect.plural(/e$/i, 'er') 8 | 9 | inflect.singular(/er$/i, '') 10 | inflect.singular(/re$/i, 'r') 11 | 12 | inflect.irregular('konto', 'konti') 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/inflections/tr.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | module Inflections 4 | ActiveSupport::Inflector.inflections(:tr) do |inflect| 5 | inflect.clear 6 | 7 | inflect.plural(/([aoıu][^aoıueöiü]{,6})$/, '\1lar') 8 | inflect.plural(/([eöiü][^aoıueöiü]{,6})$/, '\1ler') 9 | 10 | inflect.singular(/l[ae]r$/i, '') 11 | 12 | inflect.irregular('ben', 'biz') 13 | inflect.irregular('sen', 'siz') 14 | inflect.irregular('o', 'onlar') 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/inflections/kk.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | module Inflections 4 | ActiveSupport::Inflector.inflections(:kk) do |inflect| 5 | inflect.clear 6 | 7 | vowels = 'оұаыөүәіе' 8 | 9 | inflect.plural(/[кқпстфхчцшщбвгд]$/i, '\0тар') 10 | inflect.plural(/[өүәіе][^#{vowels}]*[кқпстфхчцшщбвгд]$/i, '\0тер') 11 | 12 | inflect.plural(/[лмнңжз]$/i, '\0дар') 13 | inflect.plural(/[өүәіе][^#{vowels}]*[лмнңжз]$/i, '\0дер') 14 | 15 | inflect.plural(/[#{vowels}руй]$/i, '\0лар') 16 | inflect.plural(/[өүәіе][^#{vowels}]*[#{vowels}руй]$/i, '\0лер') 17 | 18 | inflect.singular(/[тдл][ае]р$/i, '') 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/inflections/es.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | module Inflections 4 | ActiveSupport::Inflector.inflections(:es) do |inflect| 5 | inflect.clear 6 | 7 | inflect.plural(/$/, 's') 8 | inflect.plural(/([^aeéiou])$/i, '\1es') 9 | inflect.plural(/([aeiou]s)$/i, '\1') 10 | inflect.plural(/z$/i, 'ces') 11 | inflect.plural(/á([sn])$/i, 'a\1es') 12 | inflect.plural(/é([sn])$/i, 'e\1es') 13 | inflect.plural(/í([sn])$/i, 'i\1es') 14 | inflect.plural(/ó([sn])$/i, 'o\1es') 15 | inflect.plural(/ú([sn])$/i, 'u\1es') 16 | 17 | inflect.singular(/s$/, '') 18 | inflect.singular(/es$/, '') 19 | inflect.singular(/([sfj]e)s$/, '\1') 20 | inflect.singular(/ces$/, 'z') 21 | 22 | inflect.irregular('el', 'los') 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /inflections.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | require File.expand_path('../lib/inflections/version', __FILE__) 3 | 4 | Gem::Specification.new do |gem| 5 | gem.authors = ['David Celis'] 6 | gem.email = ['david@davidcelis.com'] 7 | gem.description = %q{A better set of singularization and pluralization rules for Ruby/Rails applications using ActiveSupport.} 8 | gem.summary = %q{Sane inflection rules for ActiveSupport.} 9 | gem.homepage = 'https://github.com/davidcelis/inflections' 10 | 11 | gem.files = `git ls-files`.split($\) 12 | gem.test_files = Dir.glob('test/*_test.rb') 13 | gem.name = 'inflections' 14 | gem.version = Inflections::VERSION 15 | 16 | gem.add_development_dependency 'rake' 17 | gem.add_development_dependency 'minitest' 18 | 19 | gem.add_dependency 'activesupport', '>= 4.0.0' 20 | end 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 David Celis 2 | 3 | MIT License 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 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. -------------------------------------------------------------------------------- /lib/inflections/fr.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # 3 | # These rules come from a port of ActiveSupport's Inflector to PHP: 4 | # https://github.com/ICanBoogie/Inflector/blob/master/lib/inflections/fr.php 5 | 6 | module Inflections 7 | ActiveSupport::Inflector.inflections(:fr) do |inflect| 8 | inflect.clear 9 | 10 | inflect.plural(/$/, 's') 11 | inflect.singular(/s$/, '') 12 | 13 | inflect.plural(/(bijou|caillou|chou|genou|hibou|joujou|pou|au|eu|eau)$/, '\1x') 14 | inflect.singular(/(bijou|caillou|chou|genou|hibou|joujou|pou|au|eu|eau)x$/, '\1') 15 | 16 | inflect.plural(/(bleu|émeu|landau|lieu|pneu|sarrau)$/, '\1s') 17 | inflect.plural(/al$/, 'aux') 18 | inflect.plural(/ail$/, 'ails') 19 | inflect.singular(/(journ|chev)aux$/, '\1al') 20 | inflect.singular(/ails$/, 'ail') 21 | 22 | inflect.plural(/(b|cor|ém|gemm|soupir|trav|vant|vitr)ail$/, '\1aux') 23 | inflect.singular(/(b|cor|ém|gemm|soupir|trav|vant|vitr)aux$/, '\1ail') 24 | 25 | inflect.plural(/(s|x|z)$/, '\1') 26 | 27 | inflect.irregular('monsieur', 'messieurs') 28 | inflect.irregular('madame', 'mesdames') 29 | inflect.irregular('mademoiselle', 'mesdemoiselles') 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /test/tr_test.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'test_helper' 4 | require 'inflections/tr' 5 | 6 | class TestTurkishInflections < Minitest::Test 7 | def test_regular_plurals 8 | assert_equal 'günler', 'gün'.pluralize(:tr) 9 | assert_equal 'gün', 'günler'.singularize(:tr) 10 | 11 | assert_equal 'kirazlar', 'kiraz'.pluralize(:tr) 12 | assert_equal 'kiraz', 'kirazlar'.singularize(:tr) 13 | 14 | assert_equal 'kitaplar', 'kitap'.pluralize(:tr) 15 | assert_equal 'kitap', 'kitaplar'.singularize(:tr) 16 | 17 | assert_equal 'köpekler', 'köpek'.pluralize(:tr) 18 | assert_equal 'köpek', 'köpekler'.singularize(:tr) 19 | 20 | assert_equal 'testler', 'test'.pluralize(:tr) 21 | assert_equal 'test', 'testler'.singularize(:tr) 22 | 23 | assert_equal 'üçgenler', 'üçgen'.pluralize(:tr) 24 | assert_equal 'üçgen', 'üçgenler'.singularize(:tr) 25 | end 26 | 27 | def test_irregulars 28 | assert_equal 'biz', 'ben'.pluralize(:tr) 29 | assert_equal 'ben', 'biz'.singularize(:tr) 30 | 31 | assert_equal 'siz', 'sen'.pluralize(:tr) 32 | assert_equal 'sen', 'siz'.singularize(:tr) 33 | 34 | assert_equal 'o', 'onlar'.singularize(:tr) 35 | assert_equal 'onlar', 'o'.pluralize(:tr) 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /test/nb_test.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'test_helper' 4 | require 'inflections/nb' 5 | 6 | class TestNorwegianBokmalInflections < Minitest::Test 7 | def test_svake_substantiv_er 8 | assert_equal 'hunder', 'hund'.pluralize(:nb) 9 | assert_equal 'hund', 'hunder'.singularize(:nb) 10 | 11 | assert_equal 'dager', 'dag'.pluralize(:nb) 12 | assert_equal 'dag', 'dager'.singularize(:nb) 13 | 14 | assert_equal 'tester', 'test'.pluralize(:nb) 15 | assert_equal 'test', 'tester'.singularize(:nb) 16 | end 17 | 18 | def test_svake_substantiv_r 19 | assert_equal 'lærere', 'lærer'.pluralize(:nb) 20 | assert_equal 'lærer', 'lærere'.singularize(:nb) 21 | 22 | assert_equal 'kalendere', 'kalender'.pluralize(:nb) 23 | assert_equal 'kalender', 'kalendere'.singularize(:nb) 24 | end 25 | 26 | def test_svake_substantiv_e 27 | assert_equal 'bakker', 'bakke'.pluralize(:nb) 28 | # TODO: Fix this. How do we keep this form apart from "hunder"? 29 | # assert_equal 'bakke', 'bakker'.singularize(:nb) 30 | 31 | assert_equal 'epler', 'eple'.pluralize(:nb) 32 | # assert_equal 'eple', 'epler'.singularize(:nb) 33 | end 34 | 35 | def test_sterke_verb 36 | assert_equal 'konti', 'konto'.pluralize(:nb) 37 | assert_equal 'konto', 'konti'.singularize(:nb) 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /test/it_test.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'test_helper' 4 | require 'inflections/it' 5 | 6 | class TestItalianInflections < Minitest::Test 7 | def test_plurales_regulares 8 | assert_equal 'gelati', 'gelato'.pluralize(:it) 9 | assert_equal 'gelato', 'gelati'.singularize(:it) 10 | 11 | assert_equal 'donna', 'donne'.singularize(:it) 12 | 13 | assert_equal 'mari', 'mare'.pluralize(:it) 14 | 15 | assert_equal 'oasi', 'oasi'.pluralize(:it) 16 | end 17 | 18 | def test_plurales_ending_with_accent_letter 19 | assert_equal 'città', 'città'.pluralize(:it) 20 | assert_equal 'città', 'città'.singularize(:it) 21 | 22 | assert_equal 'caffè', 'caffè'.pluralize(:it) 23 | assert_equal 'caffè', 'caffè'.singularize(:it) 24 | end 25 | 26 | def test_plurales_ending_in_go 27 | assert_equal 'aghi', 'ago'.pluralize(:it) 28 | assert_equal 'ago', 'aghi'.singularize(:it) 29 | end 30 | 31 | def test_plurales_single_sillabe 32 | assert_equal 're', 're'.pluralize(:it) 33 | assert_equal 're', 're'.singularize(:it) 34 | 35 | assert_equal 'gru', 'gru'.pluralize(:it) 36 | assert_equal 'gru', 'gru'.singularize(:it) 37 | end 38 | 39 | def test_plurales_irregulares 40 | assert_equal 'uomini', 'uomo'.pluralize(:it) 41 | assert_equal 'uomo', 'uomini'.singularize(:it) 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/inflections/it.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | module Inflections 4 | ActiveSupport::Inflector.inflections(:it) do |inflect| 5 | inflect.clear 6 | 7 | inflect.plural(/[oei]$/i, 'i') 8 | inflect.plural(/[àèìòù]$/i, '\0') 9 | inflect.plural(/^.{2,3}$/, '\0') 10 | inflect.plural(/go$/i, 'ghi') 11 | 12 | inflect.singular(/i$/i, 'o') 13 | inflect.singular(/e$/i, 'a') 14 | inflect.singular(/^.{2,3}$/, '\0') 15 | inflect.singular(/ghi$/i, 'go') 16 | 17 | inflect.irregular('uomo', 'uomini') 18 | inflect.irregular('bue', 'buoi') 19 | inflect.irregular('dio', 'dèi') 20 | inflect.irregular('ampio', 'ampi') 21 | inflect.irregular('tempio', 'templi') 22 | inflect.irregular('mio', 'miei') 23 | inflect.irregular('tuo', 'tuoi') 24 | inflect.irregular('suo', 'suoi') 25 | inflect.irregular('belga', 'belgi') 26 | inflect.irregular('euripiga', 'euripigi') 27 | inflect.irregular('bello', 'belli') 28 | inflect.irregular('mano', 'mani') 29 | inflect.irregular('ala', 'ali') 30 | inflect.irregular('arma', 'armi') 31 | inflect.irregular('eco', 'echi') 32 | inflect.irregular('sinodo', 'sinodi') 33 | inflect.irregular('centinaio', 'centinaia') 34 | inflect.irregular('migliaio', 'migliaia') 35 | inflect.irregular('paio', 'paia') 36 | inflect.irregular('prelio', 'prelia') 37 | inflect.irregular('riso', 'risa') 38 | inflect.irregular('uovo', 'uova') 39 | inflect.irregular('dito', 'dita') 40 | inflect.irregular('carcere', 'carceri') 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /test/kk_test.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'test_helper' 4 | require 'inflections/kk' 5 | 6 | class TestKazakhInflections < Minitest::Test 7 | def test_voiceless 8 | assert_equal 'сабақтар', 'сабақ'.pluralize(:kk) 9 | assert_equal 'сабақ', 'сабақтар'.singularize(:kk) 10 | 11 | assert_equal 'мектептер', 'мектеп'.pluralize(:kk) 12 | assert_equal 'мектеп', 'мектептер'.singularize(:kk) 13 | end 14 | 15 | def test_voiced 16 | assert_equal 'қағаздар', 'қағаз'.pluralize(:kk) 17 | assert_equal 'қағаз', 'қағаздар'.singularize(:kk) 18 | 19 | assert_equal 'кілемдер', 'кілем'.pluralize(:kk) 20 | assert_equal 'кілем', 'кілемдер'.singularize(:kk) 21 | 22 | assert_equal 'гүлдер', 'гүл'.pluralize(:kk) 23 | assert_equal 'гүл', 'гүлдер'.singularize(:kk) 24 | end 25 | 26 | def test_sonor 27 | assert_equal 'балалар', 'бала'.pluralize(:kk) 28 | assert_equal 'бала', 'балалар'.singularize(:kk) 29 | 30 | assert_equal 'дәрігерлер', 'дәрігер'.pluralize(:kk) 31 | assert_equal 'дәрігер', 'дәрігерлер'.singularize(:kk) 32 | 33 | assert_equal 'үйлер', 'үй'.pluralize(:kk) 34 | assert_equal 'үй', 'үйлер'.singularize(:kk) 35 | 36 | assert_equal 'ескертулер', 'ескерту'.pluralize(:kk) 37 | assert_equal 'ескерту', 'ескертулер'.singularize(:kk) 38 | 39 | assert_equal 'аурулар', 'ауру'.pluralize(:kk) 40 | assert_equal 'ауру', 'аурулар'.singularize(:kk) 41 | end 42 | 43 | def test_looks_like_plural 44 | assert_equal 'дәптерлер', 'дәптер'.pluralize(:kk) 45 | assert_equal 'дәптер', 'дәптерлер'.singularize(:kk) 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /CHANGELOG.markdown: -------------------------------------------------------------------------------- 1 | 3.2.12.20130314 (Current release) 2 | ================================= 3 | * Support for French (thanks to [Olivier Laviale](https://github.com/olvlvl) of [ICanBoogie](https://github.com/ICanBoogie/Inflector)) 4 | 5 | 3.2.12.20130305 6 | =============== 7 | * Fix #9 - a bug that was causing all strings to pluralize and singularize in Turkish. 8 | 9 | 3.2.12 10 | ====== 11 | * Support for Turkish (thanks to [Ferhat Elmas](https://github.com/ferhatelmas)) 12 | 13 | 3.2.9.20121206 14 | ============== 15 | * Support for Kazakh (thanks to [Galymzhan Kozhayev](https://github.com/galymzhan)) 16 | 17 | 3.2.9 18 | ===== 19 | * Support for Norwegian Bokmål (thanks to [Henrik Hodne](https://github.com/henrikhodne)) 20 | 21 | 3.2.8 22 | ===== 23 | * Support for British English (thanks to [creativetags](https://github.com/creativetags)) 24 | * Now versioning alongside ActiveSupport 25 | 26 | 0.0.5 27 | ===== 28 | * Rails users no longer need to specify a locale to load; inflections are automagically loaded depending on `I18n.default_locale` 29 | 30 | 0.0.4 31 | ===== 32 | * Support for Spanish (es) 33 | 34 | 0.0.3 35 | ===== 36 | * Code reorganization. Inflections will now be located under `lib/inflections/` and will be named as according to their I18n abbreviation. 37 | * Tests have also been reorganized. They live in the `test/` directory (big surprise) and, like the inflection files, should be named as according to their I18n abbreviation (`en_test.rb`, `es_test.rb`, `de_test.rb`, etc.) 38 | 39 | 0.0.2 40 | ===== 41 | * Travis CI support 42 | 43 | 0.0.1 44 | ===== 45 | * Initial version: support for English (en) 46 | -------------------------------------------------------------------------------- /test/es_test.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'test_helper' 4 | require 'inflections/es' 5 | 6 | class TestSpanishInflections < Minitest::Test 7 | def test_plurales_regulares 8 | assert_equal 'libros', 'libro'.pluralize(:es) 9 | assert_equal 'libro', 'libros'.singularize(:es) 10 | 11 | assert_equal 'radios', 'radio'.pluralize(:es) 12 | assert_equal 'radio', 'radios'.singularize(:es) 13 | 14 | assert_equal 'señores', 'señor'.pluralize(:es) 15 | assert_equal 'señor', 'señores'.singularize(:es) 16 | 17 | assert_equal 'leyes', 'ley'.pluralize(:es) 18 | assert_equal 'ley', 'leyes'.singularize(:es) 19 | end 20 | 21 | def test_plurales_que_terminan_en_z 22 | assert_equal 'meces', 'mez'.pluralize(:es) 23 | assert_equal 'luces', 'luz'.pluralize(:es) 24 | end 25 | 26 | def test_plurales_que_terminan_en_n_o_s_con_acentos 27 | assert_equal 'aviones', 'avión'.pluralize(:es) 28 | assert_equal 'intereses', 'interés'.pluralize(:es) 29 | end 30 | 31 | def test_plurales_irregulares 32 | assert_equal 'los', 'el'.pluralize(:es) 33 | assert_equal 'el', 'los'.singularize(:es) 34 | end 35 | 36 | def test_singulares_regulares 37 | assert_equal 'casa', 'casas'.singularize(:es) 38 | assert_equal 'perro', 'perros'.singularize(:es) 39 | 40 | assert_equal 'árbol', 'árboles'.singularize(:es) 41 | assert_equal 'álbum', 'álbumes'.singularize(:es) 42 | assert_equal 'mujer', 'mujeres'.singularize(:es) 43 | end 44 | 45 | def test_singulares_especiales 46 | assert_equal 'mequetrefe', 'mequetrefes'.singularize(:es) 47 | assert_equal 'pasaje', 'pasajes'.singularize(:es) 48 | assert_equal 'fase', 'fases'.singularize(:es) 49 | assert_equal 'pez', 'peces'.singularize(:es) 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /test/pt-br_test.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'test_helper' 4 | require 'inflections/pt-BR' 5 | 6 | class TestSpanishInflections < Minitest::Test 7 | def test_plurales_regulares 8 | assert_equal 'livros', 'livro'.pluralize(:pt_br) 9 | assert_equal 'livro', 'livros'.singularize(:pt_br) 10 | 11 | assert_equal 'radios', 'radio'.pluralize(:pt_br) 12 | assert_equal 'radio', 'radios'.singularize(:pt_br) 13 | 14 | assert_equal 'senhores', 'senhor'.pluralize(:pt_br) 15 | assert_equal 'senhor', 'senhores'.singularize(:pt_br) 16 | 17 | assert_equal 'leis', 'lei'.pluralize(:pt_br) 18 | assert_equal 'lei', 'leis'.singularize(:pt_br) 19 | assert_equal 'rei', 'reis'.singularize(:pt_br) 20 | end 21 | 22 | def test_plurales_que_terminam_en_z 23 | assert_equal 'luzes', 'luz'.pluralize(:pt_br) 24 | assert_equal 'juizes', 'juiz'.pluralize(:pt_br) 25 | end 26 | 27 | def test_plurais_que_terminam_en_n_o_s_con_acentos 28 | assert_equal 'aviões', 'avião'.pluralize(:pt_br) 29 | assert_equal 'cães', 'cão'.pluralize(:pt_br) 30 | assert_equal 'interesses', 'interesse'.pluralize(:pt_br) 31 | assert_equal 'ases', 'ás'.pluralize(:pt_br) 32 | assert_equal 'mãos', 'mão' .pluralize(:pt_br) 33 | assert_equal 'peões', 'peão'.pluralize(:pt_br) 34 | end 35 | 36 | def test_singulares_regulares 37 | assert_equal 'casa', 'casas'.singularize(:pt_br) 38 | assert_equal 'cão', 'cães'.singularize(:pt_br) 39 | assert_equal 'mão', 'mãos'.singularize(:pt_br) 40 | assert_equal 'peão', 'peões'.singularize(:pt_br) 41 | 42 | assert_equal 'árvore', 'árvores'.singularize(:pt_br) 43 | assert_equal 'cor', 'cores'.singularize(:pt_br) 44 | assert_equal 'álbum', 'álbums'.singularize(:pt_br) 45 | assert_equal 'mulher', 'mulheres'.singularize(:pt_br) 46 | end 47 | 48 | def test_singulares_especiales 49 | assert_equal 'nação', 'nações'.singularize(:pt_br) 50 | assert_equal 'país', 'paises'.singularize(:pt_br) 51 | assert_equal 'paises', 'país'.pluralize(:pt_br) 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /test/fr_test.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'test_helper' 4 | require 'inflections/fr' 5 | 6 | class TestFrenchInflections < Minitest::Test 7 | def test_regular_plurals 8 | assert_equal 'amis', 'ami'.pluralize(:fr) 9 | assert_equal 'ami', 'amis'.singularize(:fr) 10 | 11 | assert_equal 'fidèles', 'fidèle'.pluralize(:fr) 12 | assert_equal 'fidèle', 'fidèles'.singularize(:fr) 13 | 14 | assert_equal 'rapports', 'rapport'.pluralize(:fr) 15 | assert_equal 'rapport', 'rapports'.singularize(:fr) 16 | end 17 | 18 | def test_appending_x 19 | # -au 20 | assert_equal 'tuyaux', 'tuyau'.pluralize(:fr) 21 | assert_equal 'tuyau', 'tuyaux'.singularize(:fr) 22 | 23 | # -ou 24 | assert_equal 'genoux', 'genou'.pluralize(:fr) 25 | assert_equal 'genou', 'genoux'.singularize(:fr) 26 | 27 | # -eu 28 | assert_equal 'aveux', 'aveu'.pluralize(:fr) 29 | assert_equal 'aveu', 'aveux'.singularize(:fr) 30 | 31 | # -eau 32 | assert_equal 'nouveaux', 'nouveau'.pluralize(:fr) 33 | assert_equal 'nouveau', 'nouveaux'.singularize(:fr) 34 | end 35 | 36 | def test_exceptions_to_appending_x 37 | assert_equal 'bleus', 'bleu'.pluralize(:fr) 38 | assert_equal 'bleu', 'bleus'.singularize(:fr) 39 | 40 | assert_equal 'landaus', 'landau'.pluralize(:fr) 41 | assert_equal 'landau', 'landaus'.singularize(:fr) 42 | 43 | assert_equal 'genoux', 'genou'.pluralize(:fr) 44 | assert_equal 'genou', 'genoux'.singularize(:fr) 45 | end 46 | 47 | def test_ending_in_al 48 | assert_equal 'journaux', 'journal'.pluralize(:fr) 49 | assert_equal 'journal', 'journaux'.singularize(:fr) 50 | end 51 | 52 | def test_ending_in_ail 53 | assert_equal 'détails', 'détail'.pluralize(:fr) 54 | assert_equal 'détail', 'détails'.singularize(:fr) 55 | end 56 | 57 | def test_exceptions_to_ending_in_ail 58 | assert_equal 'travaux', 'travail'.pluralize(:fr) 59 | assert_equal 'travail', 'travaux'.singularize(:fr) 60 | 61 | assert_equal 'baux', 'bail'.pluralize(:fr) 62 | assert_equal 'bail', 'baux'.singularize(:fr) 63 | 64 | assert_equal 'émaux', 'émail'.pluralize(:fr) 65 | assert_equal 'émail', 'émaux'.singularize(:fr) 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /lib/inflections/pt-BR.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # Be sure to restart your server when you modify this file. 3 | 4 | # Add new inflection rules using the following format 5 | # (all these examples are active by default): 6 | # ActiveSupport::Inflector.inflections do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | module Inflections 13 | ActiveSupport::Inflector.inflections(:pt_br) do |inflect| 14 | inflect.clear 15 | 16 | inflect.plural(/$/, 's') 17 | inflect.plural(/(s)$/i, '\1') 18 | inflect.plural(/(z|r)$/i, '\1es') 19 | inflect.plural(/al$/i, 'ais') 20 | inflect.plural(/el$/i, 'eis') 21 | inflect.plural(/ol$/i, 'ois') 22 | inflect.plural(/ul$/i, 'uis') 23 | inflect.plural(/([^aeou])il$/i, '\1is') 24 | inflect.plural(/m$/i, 'ns') 25 | inflect.plural(/^(japon|escoc|ingl|dinamarqu|fregu|portugu)ês$/i, '\1eses') 26 | inflect.plural(/^(|g)ás$/i, '\1ases') 27 | inflect.plural(/ão$/i, 'ões') 28 | inflect.plural(/^(irm|m)ão$/i, '\1ãos') 29 | inflect.plural(/^(alem|c|p)ão$/i, '\1ães') 30 | 31 | # Sem acentos... 32 | inflect.plural(/ao$/i, 'oes') 33 | inflect.plural(/^(irm|m)ao$/i, '\1aos') 34 | inflect.plural(/^(alem|c|p)ao$/i, '\1aes') 35 | 36 | inflect.singular(/([^ê])s$/i, '\1') 37 | inflect.singular(/^(á|gá)s$/i, '\1s') 38 | inflect.singular(/(r|z)es$/i, '\1') 39 | inflect.singular(/([^p])ais$/i, '\1al') 40 | inflect.singular(/éis$/i, 'el') 41 | inflect.singular(/eis$/i, 'ei') 42 | inflect.singular(/ois$/i, 'ol') 43 | inflect.singular(/uis$/i, 'ul') 44 | inflect.singular(/(r|t|f|v)is$/i, '\1il') 45 | inflect.singular(/ns$/i, 'm') 46 | inflect.singular(/sses$/i, 'sse') 47 | inflect.singular(/^(.*[^s]s)es$/i, '\1') 48 | inflect.singular(/(ãe|ão|õe)s$/, 'ão') 49 | inflect.singular(/(ae|ao|oe)s$/, 'ao') 50 | inflect.singular(/(japon|escoc|ingl|dinamarqu|fregu|portugu)eses$/i, '\1ês') 51 | inflect.singular(/^(g|)ases$/i, '\1ás') 52 | 53 | # Incontáveis 54 | inflect.uncountable %w( tórax tênis ônibus lápis fênix ) 55 | 56 | # Irregulares 57 | inflect.irregular "país", "paises" 58 | inflect.irregular "árvore", "árvores" 59 | inflect.irregular "cadáver", "cadáveres" 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Inflections [![Build Status](https://secure.travis-ci.org/davidcelis/inflections.png)](http://travis-ci.org/davidcelis/inflections) 2 | 3 | Inflections is a repository containing non-English singularization and pluralization rules for Rails, supporting the multilingual ActiveSupport::Inflector in Rails 4. 4 | 5 | ## Languages Currently Supported 6 | 7 | * Spanish (es) 8 | * French (fr) 9 | * Kazakh (kk) 10 | * Norwegian Bokmål (nb) 11 | * Brazilian Portugues (pt-BR) 12 | * Turkish (tr) 13 | * Italian (it) 14 | 15 | If you are fluent in a language not yet included in this gem, _please_ consider creating a list of inflections and submitting a pull request. 16 | 17 | ## Installation 18 | 19 | Add the following to your application's Gemfile: 20 | 21 | ```ruby 22 | gem 'inflections' 23 | ``` 24 | 25 | And then execute: 26 | 27 | ```bash 28 | $ bundle 29 | ``` 30 | 31 | ## Usage 32 | 33 | To inflect strings in a different locale: 34 | 35 | ```ruby 36 | 'persona'.pluralize(:es) 37 | # => "personas" 38 | 'madame'.pluralize(:fr) 39 | # => "mesdames" 40 | ``` 41 | 42 | Define your own additional rules as such: 43 | 44 | ```ruby 45 | ActiveSupport::Inflector.inflections(:en) do |inflect| 46 | inflect.singular /(phase)s$/i, '\1' 47 | inflect.plural /(shel|kni)fe/, '\1ves' 48 | inflect.irregular 'foot', 'feet' 49 | inflect.uncountable %w[money fish] 50 | end 51 | ``` 52 | 53 | # Rails < 4.0.0 54 | 55 | If you're not using ActiveSupport 4, the [multilingual Inflector](http://davidcel.is/posts/edge-rails-a-multilingual-inflector/) won't be supported. You should install inflections 3.2.x and you'll have to choose which locale you use by requiring a specific file: 56 | 57 | ```ruby 58 | gem 'inflections', '~> 3.2', require: 'inflections/es' 59 | ``` 60 | 61 | Note that this will override the default set of English rules that come with Rails. You should do this only if you plan on your constants and code itself not being in English. 62 | 63 | ## Contributing 64 | 65 | Please note that pull requests for already supported languages will only be accepted for rules that are in error or a potentially missed rule. If your change is an exception to an existing rule, that exception must occur _frequently_ and must involve words used more frequently than the regular plurals. If your change is an irregularity, it must be a word that is arguably _frequently_ encountered in applications that would use ActiveSupport. The default list of inflections is meant to be short. 66 | 67 | 1. Fork it 68 | 2. Create your feature branch (`git checkout -b my-new-feature`) 69 | 3. Commit your changes (`git commit -am 'Add some feature'`) with tests 70 | 4. Push to the branch (`git push origin my-new-feature`) 71 | 5. Create a new Pull Request 72 | --------------------------------------------------------------------------------