├── .github └── workflows │ └── go.yml ├── LICENSE ├── README.md ├── go.mod ├── inflections.go └── inflections_test.go /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | 3 | on: 4 | push: 5 | branches: ['*'] 6 | tags: ['v*'] 7 | pull_request: 8 | branches: ['*'] 9 | 10 | jobs: 11 | 12 | build: 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | matrix: 16 | os: ['ubuntu-latest'] 17 | go: ['stable'] 18 | 19 | steps: 20 | - name: Checkout code 21 | uses: actions/checkout@v4 22 | 23 | - name: Set up Go 24 | uses: actions/setup-go@v4 25 | with: 26 | cache: false 27 | go-version: ${{ matrix.go }} 28 | 29 | - name: Download Dependencies 30 | run: go mod download 31 | 32 | - name: Build 33 | run: go build -v ./... 34 | 35 | - name: Test 36 | run: go test -v ./... 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 - Jinzhu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Inflection 2 | 3 | Inflection pluralizes and singularizes English nouns 4 | 5 | [![Build Status](https://github.com/jinzhu/inflection/actions/workflows/go.yml/badge.svg)](https://github.com/jinzhu/inflection/actions/workflows/go.yml) 6 | 7 | ## Basic Usage 8 | 9 | ```go 10 | inflection.Plural("person") => "people" 11 | inflection.Plural("Person") => "People" 12 | inflection.Plural("PERSON") => "PEOPLE" 13 | inflection.Plural("bus") => "buses" 14 | inflection.Plural("BUS") => "BUSES" 15 | inflection.Plural("Bus") => "Buses" 16 | 17 | inflection.Singular("people") => "person" 18 | inflection.Singular("People") => "Person" 19 | inflection.Singular("PEOPLE") => "PERSON" 20 | inflection.Singular("buses") => "bus" 21 | inflection.Singular("BUSES") => "BUS" 22 | inflection.Singular("Buses") => "Bus" 23 | 24 | inflection.Plural("FancyPerson") => "FancyPeople" 25 | inflection.Singular("FancyPeople") => "FancyPerson" 26 | ``` 27 | 28 | ## Register Rules 29 | 30 | Standard rules are from Rails's ActiveSupport (https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflections.rb) 31 | 32 | If you want to register more rules, follow: 33 | 34 | ```go 35 | inflection.AddUncountable("fish") 36 | inflection.AddIrregular("person", "people") 37 | inflection.AddPlural("(bu)s$", "${1}ses") // "bus" => "buses" / "BUS" => "BUSES" / "Bus" => "Buses" 38 | inflection.AddSingular("(bus)(es)?$", "${1}") // "buses" => "bus" / "Buses" => "Bus" / "BUSES" => "BUS" 39 | ``` 40 | 41 | ## Contributing 42 | 43 | You can help to make the project better, check out [http://gorm.io/contribute.html](http://gorm.io/contribute.html) for things you can do. 44 | 45 | ## Author 46 | 47 | **jinzhu** 48 | 49 | * 50 | * 51 | * 52 | 53 | ## License 54 | 55 | Released under the [MIT License](http://www.opensource.org/licenses/MIT). 56 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/jinzhu/inflection 2 | 3 | go 1.15 4 | -------------------------------------------------------------------------------- /inflections.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package inflection pluralizes and singularizes English nouns. 3 | 4 | inflection.Plural("person") => "people" 5 | inflection.Plural("Person") => "People" 6 | inflection.Plural("PERSON") => "PEOPLE" 7 | 8 | inflection.Singular("people") => "person" 9 | inflection.Singular("People") => "Person" 10 | inflection.Singular("PEOPLE") => "PERSON" 11 | 12 | inflection.Plural("FancyPerson") => "FancydPeople" 13 | inflection.Singular("FancyPeople") => "FancydPerson" 14 | 15 | Standard rules are from Rails's ActiveSupport (https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflections.rb) 16 | 17 | If you want to register more rules, follow: 18 | 19 | inflection.AddUncountable("fish") 20 | inflection.AddIrregular("person", "people") 21 | inflection.AddPlural("(bu)s$", "${1}ses") # "bus" => "buses" / "BUS" => "BUSES" / "Bus" => "Buses" 22 | inflection.AddSingular("(bus)(es)?$", "${1}") # "buses" => "bus" / "Buses" => "Bus" / "BUSES" => "BUS" 23 | */ 24 | package inflection 25 | 26 | import ( 27 | "regexp" 28 | "strings" 29 | ) 30 | 31 | type inflection struct { 32 | regexp *regexp.Regexp 33 | replace string 34 | } 35 | 36 | // Regular is a regexp find replace inflection 37 | type Regular struct { 38 | find string 39 | replace string 40 | } 41 | 42 | // Irregular is a hard replace inflection, 43 | // containing both singular and plural forms 44 | type Irregular struct { 45 | singular string 46 | plural string 47 | } 48 | 49 | // RegularSlice is a slice of Regular inflections 50 | type RegularSlice []Regular 51 | 52 | // IrregularSlice is a slice of Irregular inflections 53 | type IrregularSlice []Irregular 54 | 55 | var pluralInflections = RegularSlice{ 56 | {"([a-z])$", "${1}s"}, 57 | {"s$", "s"}, 58 | {"^(ax|test)is$", "${1}es"}, 59 | {"(octop|vir)us$", "${1}i"}, 60 | {"(octop|vir)i$", "${1}i"}, 61 | {"(alias|status|campus)$", "${1}es"}, 62 | {"(bu)s$", "${1}ses"}, 63 | {"(buffal|tomat)o$", "${1}oes"}, 64 | {"([ti])um$", "${1}a"}, 65 | {"([ti])a$", "${1}a"}, 66 | {"sis$", "ses"}, 67 | {"(?:([^f])fe|([lr])f)$", "${1}${2}ves"}, 68 | {"(hive)$", "${1}s"}, 69 | {"([^aeiouy]|qu)y$", "${1}ies"}, 70 | {"(x|ch|ss|sh)$", "${1}es"}, 71 | {"(matr|vert|ind)(?:ix|ex)$", "${1}ices"}, 72 | {"^(m|l)ouse$", "${1}ice"}, 73 | {"^(m|l)ice$", "${1}ice"}, 74 | {"^(ox)$", "${1}en"}, 75 | {"^(oxen)$", "${1}"}, 76 | {"(quiz)$", "${1}zes"}, 77 | {"(drive)$", "${1}s"}, 78 | } 79 | 80 | var singularInflections = RegularSlice{ 81 | {"s$", ""}, 82 | {"(ss)$", "${1}"}, 83 | {"(n)ews$", "${1}ews"}, 84 | {"([ti])a$", "${1}um"}, 85 | {"((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$", "${1}sis"}, 86 | {"(^analy)(sis|ses)$", "${1}sis"}, 87 | {"([^f])ves$", "${1}fe"}, 88 | {"(hive)s$", "${1}"}, 89 | {"(tive)s$", "${1}"}, 90 | {"([lr])ves$", "${1}f"}, 91 | {"([^aeiouy]|qu)ies$", "${1}y"}, 92 | {"(s)eries$", "${1}eries"}, 93 | {"(m)ovies$", "${1}ovie"}, 94 | {"(c)ookies$", "${1}ookie"}, 95 | {"(x|ch|ss|sh)es$", "${1}"}, 96 | {"^(m|l)ice$", "${1}ouse"}, 97 | {"(bus|campus)(es)?$", "${1}"}, 98 | {"(o)es$", "${1}"}, 99 | {"(shoe)s$", "${1}"}, 100 | {"(cris|test)(is|es)$", "${1}is"}, 101 | {"^(a)x[ie]s$", "${1}xis"}, 102 | {"(octop|vir)(us|i)$", "${1}us"}, 103 | {"(alias|status)(es)?$", "${1}"}, 104 | {"^(ox)en", "${1}"}, 105 | {"(vert|ind)ices$", "${1}ex"}, 106 | {"(matr)ices$", "${1}ix"}, 107 | {"(quiz)zes$", "${1}"}, 108 | {"(database)s$", "${1}"}, 109 | {"(drive)s$", "${1}"}, 110 | } 111 | 112 | var irregularInflections = IrregularSlice{ 113 | {"person", "people"}, 114 | {"man", "men"}, 115 | {"child", "children"}, 116 | {"sex", "sexes"}, 117 | {"move", "moves"}, 118 | {"ombie", "ombies"}, 119 | {"goose", "geese"}, 120 | {"foot", "feet"}, 121 | {"moose", "moose"}, 122 | {"tooth", "teeth"}, 123 | {"leaf", "leaves"}, 124 | {"chassis", "chassis"}, 125 | } 126 | 127 | var uncountableInflections = []string{"equipment", "information", "rice", "money", "species", "series", "fish", "sheep", "jeans", "police", "milk", "salt", "time", "water", "paper", "food", "art", "cash", "music", "help", "luck", "oil", "progress", "rain", "research", "shopping", "software", "traffic"} 128 | 129 | var compiledPluralMaps []inflection 130 | var compiledSingularMaps []inflection 131 | 132 | func compile() { 133 | compiledPluralMaps, compiledSingularMaps = nil, nil 134 | for _, uncountable := range uncountableInflections { 135 | inf := inflection{ 136 | regexp: regexp.MustCompile("^(?i)(" + uncountable + ")$"), 137 | replace: "${1}", 138 | } 139 | compiledPluralMaps = append(compiledPluralMaps, inf) 140 | compiledSingularMaps = append(compiledSingularMaps, inf) 141 | } 142 | 143 | for _, value := range irregularInflections { 144 | infs := []inflection{ 145 | {regexp: regexp.MustCompile(strings.ToUpper(value.singular) + "$"), replace: strings.ToUpper(value.plural)}, 146 | {regexp: regexp.MustCompile(strings.Title(value.singular) + "$"), replace: strings.Title(value.plural)}, 147 | {regexp: regexp.MustCompile(value.singular + "$"), replace: value.plural}, 148 | } 149 | compiledPluralMaps = append(compiledPluralMaps, infs...) 150 | } 151 | 152 | for _, value := range irregularInflections { 153 | infs := []inflection{ 154 | {regexp: regexp.MustCompile(strings.ToUpper(value.plural) + "$"), replace: strings.ToUpper(value.singular)}, 155 | {regexp: regexp.MustCompile(strings.Title(value.plural) + "$"), replace: strings.Title(value.singular)}, 156 | {regexp: regexp.MustCompile(value.plural + "$"), replace: value.singular}, 157 | } 158 | compiledSingularMaps = append(compiledSingularMaps, infs...) 159 | } 160 | 161 | for i := len(pluralInflections) - 1; i >= 0; i-- { 162 | value := pluralInflections[i] 163 | infs := []inflection{ 164 | {regexp: regexp.MustCompile(strings.ToUpper(value.find)), replace: strings.ToUpper(value.replace)}, 165 | {regexp: regexp.MustCompile(value.find), replace: value.replace}, 166 | {regexp: regexp.MustCompile("(?i)" + value.find), replace: value.replace}, 167 | } 168 | compiledPluralMaps = append(compiledPluralMaps, infs...) 169 | } 170 | 171 | for i := len(singularInflections) - 1; i >= 0; i-- { 172 | value := singularInflections[i] 173 | infs := []inflection{ 174 | {regexp: regexp.MustCompile(strings.ToUpper(value.find)), replace: strings.ToUpper(value.replace)}, 175 | {regexp: regexp.MustCompile(value.find), replace: value.replace}, 176 | {regexp: regexp.MustCompile("(?i)" + value.find), replace: value.replace}, 177 | } 178 | compiledSingularMaps = append(compiledSingularMaps, infs...) 179 | } 180 | } 181 | 182 | func init() { 183 | compile() 184 | } 185 | 186 | // AddPlural adds a plural inflection 187 | func AddPlural(find, replace string) { 188 | pluralInflections = append(pluralInflections, Regular{find, replace}) 189 | compile() 190 | } 191 | 192 | // AddSingular adds a singular inflection 193 | func AddSingular(find, replace string) { 194 | singularInflections = append(singularInflections, Regular{find, replace}) 195 | compile() 196 | } 197 | 198 | // AddIrregular adds an irregular inflection 199 | func AddIrregular(singular, plural string) { 200 | irregularInflections = append(irregularInflections, Irregular{singular, plural}) 201 | compile() 202 | } 203 | 204 | // AddUncountable adds an uncountable inflection 205 | func AddUncountable(values ...string) { 206 | uncountableInflections = append(uncountableInflections, values...) 207 | compile() 208 | } 209 | 210 | // GetPlural retrieves the plural inflection values 211 | func GetPlural() RegularSlice { 212 | plurals := make(RegularSlice, len(pluralInflections)) 213 | copy(plurals, pluralInflections) 214 | return plurals 215 | } 216 | 217 | // GetSingular retrieves the singular inflection values 218 | func GetSingular() RegularSlice { 219 | singulars := make(RegularSlice, len(singularInflections)) 220 | copy(singulars, singularInflections) 221 | return singulars 222 | } 223 | 224 | // GetIrregular retrieves the irregular inflection values 225 | func GetIrregular() IrregularSlice { 226 | irregular := make(IrregularSlice, len(irregularInflections)) 227 | copy(irregular, irregularInflections) 228 | return irregular 229 | } 230 | 231 | // GetUncountable retrieves the uncountable inflection values 232 | func GetUncountable() []string { 233 | uncountables := make([]string, len(uncountableInflections)) 234 | copy(uncountables, uncountableInflections) 235 | return uncountables 236 | } 237 | 238 | // SetPlural sets the plural inflections slice 239 | func SetPlural(inflections RegularSlice) { 240 | pluralInflections = inflections 241 | compile() 242 | } 243 | 244 | // SetSingular sets the singular inflections slice 245 | func SetSingular(inflections RegularSlice) { 246 | singularInflections = inflections 247 | compile() 248 | } 249 | 250 | // SetIrregular sets the irregular inflections slice 251 | func SetIrregular(inflections IrregularSlice) { 252 | irregularInflections = inflections 253 | compile() 254 | } 255 | 256 | // SetUncountable sets the uncountable inflections slice 257 | func SetUncountable(inflections []string) { 258 | uncountableInflections = inflections 259 | compile() 260 | } 261 | 262 | // Plural converts a word to its plural form 263 | func Plural(str string) string { 264 | for _, inflection := range compiledPluralMaps { 265 | if inflection.regexp.MatchString(str) { 266 | return inflection.regexp.ReplaceAllString(str, inflection.replace) 267 | } 268 | } 269 | return str 270 | } 271 | 272 | // Singular converts a word to its singular form 273 | func Singular(str string) string { 274 | for _, inflection := range compiledSingularMaps { 275 | if inflection.regexp.MatchString(str) { 276 | return inflection.regexp.ReplaceAllString(str, inflection.replace) 277 | } 278 | } 279 | return str 280 | } 281 | -------------------------------------------------------------------------------- /inflections_test.go: -------------------------------------------------------------------------------- 1 | package inflection 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | var inflections = map[string]string{ 9 | "star": "stars", 10 | "STAR": "STARS", 11 | "Star": "Stars", 12 | "bus": "buses", 13 | "fish": "fish", 14 | "mouse": "mice", 15 | "query": "queries", 16 | "ability": "abilities", 17 | "agency": "agencies", 18 | "movie": "movies", 19 | "archive": "archives", 20 | "index": "indices", 21 | "wife": "wives", 22 | "safe": "saves", 23 | "half": "halves", 24 | "move": "moves", 25 | "salesperson": "salespeople", 26 | "person": "people", 27 | "spokesman": "spokesmen", 28 | "man": "men", 29 | "woman": "women", 30 | "basis": "bases", 31 | "diagnosis": "diagnoses", 32 | "diagnosis_a": "diagnosis_as", 33 | "datum": "data", 34 | "medium": "media", 35 | "stadium": "stadia", 36 | "analysis": "analyses", 37 | "node_child": "node_children", 38 | "child": "children", 39 | "experience": "experiences", 40 | "day": "days", 41 | "comment": "comments", 42 | "foobar": "foobars", 43 | "newsletter": "newsletters", 44 | "old_news": "old_news", 45 | "news": "news", 46 | "series": "series", 47 | "species": "species", 48 | "quiz": "quizzes", 49 | "perspective": "perspectives", 50 | "ox": "oxen", 51 | "photo": "photos", 52 | "buffalo": "buffaloes", 53 | "tomato": "tomatoes", 54 | "dwarf": "dwarves", 55 | "elf": "elves", 56 | "information": "information", 57 | "equipment": "equipment", 58 | "criterion": "criteria", 59 | "foot": "feet", 60 | "goose": "geese", 61 | "moose": "moose", 62 | "tooth": "teeth", 63 | "milk": "milk", 64 | "salt": "salt", 65 | "time": "time", 66 | "water": "water", 67 | "paper": "paper", 68 | "music": "music", 69 | "help": "help", 70 | "luck": "luck", 71 | "oil": "oil", 72 | "progress": "progress", 73 | "rain": "rain", 74 | "research": "research", 75 | "shopping": "shopping", 76 | "software": "software", 77 | "traffic": "traffic", 78 | "zombie": "zombies", 79 | "campus": "campuses", 80 | "harddrive": "harddrives", 81 | "drive": "drives", 82 | "leaf": "leaves", 83 | } 84 | 85 | // storage is used to restore the state of the global variables 86 | // on each test execution, to ensure no global state pollution 87 | type storage struct { 88 | singulars RegularSlice 89 | plurals RegularSlice 90 | irregulars IrregularSlice 91 | uncountables []string 92 | } 93 | 94 | var backup = storage{} 95 | 96 | func init() { 97 | AddIrregular("criterion", "criteria") 98 | copy(backup.singulars, singularInflections) 99 | copy(backup.plurals, pluralInflections) 100 | copy(backup.irregulars, irregularInflections) 101 | copy(backup.uncountables, uncountableInflections) 102 | } 103 | 104 | func restore() { 105 | copy(singularInflections, backup.singulars) 106 | copy(pluralInflections, backup.plurals) 107 | copy(irregularInflections, backup.irregulars) 108 | copy(uncountableInflections, backup.uncountables) 109 | } 110 | 111 | func TestPlural(t *testing.T) { 112 | for key, value := range inflections { 113 | if v := Plural(strings.ToUpper(key)); v != strings.ToUpper(value) { 114 | t.Errorf("%v's plural should be %v, but got %v", strings.ToUpper(key), strings.ToUpper(value), v) 115 | } 116 | 117 | if v := Plural(strings.Title(key)); v != strings.Title(value) { 118 | t.Errorf("%v's plural should be %v, but got %v", strings.Title(key), strings.Title(value), v) 119 | } 120 | 121 | if v := Plural(key); v != value { 122 | t.Errorf("%v's plural should be %v, but got %v", key, value, v) 123 | } 124 | } 125 | } 126 | 127 | func TestSingular(t *testing.T) { 128 | for key, value := range inflections { 129 | if v := Singular(strings.ToUpper(value)); v != strings.ToUpper(key) { 130 | t.Errorf("%v's singular should be %v, but got %v", strings.ToUpper(value), strings.ToUpper(key), v) 131 | } 132 | 133 | if v := Singular(strings.Title(value)); v != strings.Title(key) { 134 | t.Errorf("%v's singular should be %v, but got %v", strings.Title(value), strings.Title(key), v) 135 | } 136 | 137 | if v := Singular(value); v != key { 138 | t.Errorf("%v's singular should be %v, but got %v", value, key, v) 139 | } 140 | } 141 | } 142 | 143 | func TestAddPlural(t *testing.T) { 144 | defer restore() 145 | ln := len(pluralInflections) 146 | AddPlural("", "") 147 | if ln+1 != len(pluralInflections) { 148 | t.Errorf("Expected len %d, got %d", ln+1, len(pluralInflections)) 149 | } 150 | } 151 | 152 | func TestAddSingular(t *testing.T) { 153 | defer restore() 154 | ln := len(singularInflections) 155 | AddSingular("", "") 156 | if ln+1 != len(singularInflections) { 157 | t.Errorf("Expected len %d, got %d", ln+1, len(singularInflections)) 158 | } 159 | } 160 | 161 | func TestAddIrregular(t *testing.T) { 162 | defer restore() 163 | ln := len(irregularInflections) 164 | AddIrregular("", "") 165 | if ln+1 != len(irregularInflections) { 166 | t.Errorf("Expected len %d, got %d", ln+1, len(irregularInflections)) 167 | } 168 | } 169 | 170 | func TestAddUncountable(t *testing.T) { 171 | defer restore() 172 | ln := len(uncountableInflections) 173 | AddUncountable("", "") 174 | if ln+2 != len(uncountableInflections) { 175 | t.Errorf("Expected len %d, got %d", ln+2, len(uncountableInflections)) 176 | } 177 | } 178 | 179 | func TestGetPlural(t *testing.T) { 180 | plurals := GetPlural() 181 | if len(plurals) != len(pluralInflections) { 182 | t.Errorf("Expected len %d, got %d", len(plurals), len(pluralInflections)) 183 | } 184 | } 185 | 186 | func TestGetSingular(t *testing.T) { 187 | singular := GetSingular() 188 | if len(singular) != len(singularInflections) { 189 | t.Errorf("Expected len %d, got %d", len(singular), len(singularInflections)) 190 | } 191 | } 192 | 193 | func TestGetIrregular(t *testing.T) { 194 | irregular := GetIrregular() 195 | if len(irregular) != len(irregularInflections) { 196 | t.Errorf("Expected len %d, got %d", len(irregular), len(irregularInflections)) 197 | } 198 | } 199 | 200 | func TestGetUncountable(t *testing.T) { 201 | uncountables := GetUncountable() 202 | if len(uncountables) != len(uncountableInflections) { 203 | t.Errorf("Expected len %d, got %d", len(uncountables), len(uncountableInflections)) 204 | } 205 | } 206 | 207 | func TestSetPlural(t *testing.T) { 208 | defer restore() 209 | SetPlural(RegularSlice{{}, {}}) 210 | if len(pluralInflections) != 2 { 211 | t.Errorf("Expected len 2, got %d", len(pluralInflections)) 212 | } 213 | } 214 | 215 | func TestSetSingular(t *testing.T) { 216 | defer restore() 217 | SetSingular(RegularSlice{{}, {}}) 218 | if len(singularInflections) != 2 { 219 | t.Errorf("Expected len 2, got %d", len(singularInflections)) 220 | } 221 | } 222 | 223 | func TestSetIrregular(t *testing.T) { 224 | defer restore() 225 | SetIrregular(IrregularSlice{{}, {}}) 226 | if len(irregularInflections) != 2 { 227 | t.Errorf("Expected len 2, got %d", len(irregularInflections)) 228 | } 229 | } 230 | 231 | func TestSetUncountable(t *testing.T) { 232 | defer restore() 233 | SetUncountable([]string{"", ""}) 234 | if len(uncountableInflections) != 2 { 235 | t.Errorf("Expected len 2, got %d", len(uncountableInflections)) 236 | } 237 | } 238 | --------------------------------------------------------------------------------