tr8n_core 4.0.4 → 4.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +44 -6
  4. data/lib/tr8n/api_client.rb +109 -0
  5. data/lib/tr8n/application.rb +14 -96
  6. data/lib/tr8n/base.rb +7 -2
  7. data/lib/tr8n/cache.rb +2 -1
  8. data/lib/tr8n/cache_adapters/cdb.rb +2 -1
  9. data/lib/tr8n/cache_adapters/file.rb +2 -1
  10. data/lib/tr8n/cache_adapters/memcache.rb +2 -1
  11. data/lib/tr8n/cache_adapters/redis.rb +2 -1
  12. data/lib/tr8n/component.rb +2 -1
  13. data/lib/tr8n/config.rb +13 -3
  14. data/lib/tr8n/decorators/base.rb +2 -1
  15. data/lib/tr8n/decorators/default.rb +2 -1
  16. data/lib/tr8n/decorators/html.rb +2 -1
  17. data/lib/tr8n/exception.rb +2 -1
  18. data/lib/tr8n/language.rb +9 -3
  19. data/lib/tr8n/language_case.rb +5 -1
  20. data/lib/tr8n/language_case_rule.rb +2 -1
  21. data/lib/tr8n/language_context.rb +4 -1
  22. data/lib/tr8n/language_context_rule.rb +2 -1
  23. data/lib/tr8n/logger.rb +3 -2
  24. data/lib/tr8n/rules_engine/evaluator.rb +2 -1
  25. data/lib/tr8n/rules_engine/parser.rb +2 -1
  26. data/lib/tr8n/session.rb +21 -7
  27. data/lib/tr8n/source.rb +3 -2
  28. data/lib/tr8n/tokens/data.rb +319 -325
  29. data/lib/tr8n/tokens/data_tokenizer.rb +6 -1
  30. data/lib/tr8n/tokens/decoration_tokenizer.rb +15 -5
  31. data/lib/tr8n/tokens/hidden.rb +2 -1
  32. data/lib/tr8n/tokens/method.rb +4 -3
  33. data/lib/tr8n/tokens/transform.rb +22 -10
  34. data/lib/tr8n/translation.rb +6 -8
  35. data/lib/tr8n/translation_key.rb +11 -9
  36. data/lib/tr8n/translator.rb +2 -1
  37. data/lib/tr8n/utils.rb +6 -1
  38. data/lib/tr8n_core.rb +1 -1
  39. data/lib/tr8n_core/ext/array.rb +1 -1
  40. data/lib/tr8n_core/ext/date.rb +1 -1
  41. data/lib/tr8n_core/ext/fixnum.rb +1 -1
  42. data/lib/tr8n_core/ext/hash.rb +1 -1
  43. data/lib/tr8n_core/ext/string.rb +1 -1
  44. data/lib/tr8n_core/ext/time.rb +1 -1
  45. data/lib/tr8n_core/generators/cache/base.rb +1 -1
  46. data/lib/tr8n_core/generators/cache/cdb.rb +1 -1
  47. data/lib/tr8n_core/generators/cache/file.rb +1 -1
  48. data/lib/tr8n_core/languages/en-US.json +1362 -0
  49. data/lib/tr8n_core/version.rb +2 -2
  50. data/spec/language_case_spec.rb +3 -3
  51. data/spec/tokens/data_spec.rb +38 -84
  52. metadata +5 -3
@@ -1,5 +1,6 @@
1
+ # encoding: UTF-8
1
2
  #--
2
- # Copyright (c) 2014 Michael Berkovich, tr8nhub.com
3
+ # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
3
4
  #
4
5
  # Permission is hereby granted, free of charge, to any person obtaining
5
6
  # a copy of this software and associated documentation files (the
@@ -47,6 +48,10 @@ module Tr8n
47
48
  [Tr8n::Tokens::Data, Tr8n::Tokens::Hidden, Tr8n::Tokens::Method, Tr8n::Tokens::Transform]
48
49
  end
49
50
 
51
+ def self.required?(label)
52
+ label.index("{")
53
+ end
54
+
50
55
  def initialize(text, context={}, opts={})
51
56
  self.text = text
52
57
  self.context = context
@@ -1,5 +1,6 @@
1
+ # encoding: UTF-8
1
2
  #--
2
- # Copyright (c) 2014 Michael Berkovich, tr8nhub.com
3
+ # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
3
4
  #
4
5
  # Permission is hereby granted, free of charge, to any person obtaining
5
6
  # a copy of this software and associated documentation files (the
@@ -51,6 +52,10 @@ module Tr8n
51
52
  RE_LONG_TOKEN_END = '\[\/[\w]*\]'
52
53
  RE_TEXT = '[^\[\]]+' #'[\w\s!.:{}\(\)\|,?]*'
53
54
 
55
+ def self.required?(label)
56
+ label.index("[")
57
+ end
58
+
54
59
  def initialize(text, context = {}, opts = {})
55
60
  @text = "[#{RESERVED_TOKEN}]#{text}[/#{RESERVED_TOKEN}]"
56
61
  @context = context
@@ -109,8 +114,10 @@ module Tr8n
109
114
 
110
115
  def default_decoration(token_name, token_value)
111
116
  default_decoration = Tr8n.config.default_token_value(token_name, :decoration)
117
+
112
118
  unless default_decoration
113
- raise Tr8n::Exception.new("Invalid decoration token value #{token_name}")
119
+ Tr8n.logger.error("Invalid decoration token value for #{token_name} in #{text}")
120
+ return token_value
114
121
  end
115
122
 
116
123
  default_decoration = default_decoration.clone
@@ -142,7 +149,8 @@ module Tr8n
142
149
  return default_decoration
143
150
  end
144
151
 
145
- raise Tr8n::Exception.new("Don't know how to process decoration token value")
152
+ Tr8n.logger.error("Don't know how to process decoration token value for #{token_name} in #{text}")
153
+ token_value
146
154
  end
147
155
 
148
156
  def allowed_token?(token)
@@ -169,14 +177,16 @@ module Tr8n
169
177
  return method.to_s.gsub("{$0}", value)
170
178
  end
171
179
 
172
- raise Tr8n::Exception.new("Invalid decoration token value")
180
+ Tr8n.logger.error("Invalid decoration token value for #{token} in #{text}")
181
+ return value
173
182
  end
174
183
 
175
184
  if Tr8n.config.default_token_value(token, :decoration)
176
185
  return default_decoration(token, value)
177
186
  end
178
187
 
179
- raise Tr8n::Exception.new("Missing decoration token value")
188
+ Tr8n.logger.error("Missing decoration token value for #{token} in #{text}")
189
+ value
180
190
  end
181
191
 
182
192
  def evaluate(expr)
@@ -1,5 +1,6 @@
1
+ # encoding: UTF-8
1
2
  #--
2
- # Copyright (c) 2014 Michael Berkovich, tr8nhub.com
3
+ # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
3
4
  #
4
5
  # Permission is hereby granted, free of charge, to any person obtaining
5
6
  # a copy of this software and associated documentation files (the
@@ -1,5 +1,6 @@
1
+ # encoding: UTF-8
1
2
  #--
2
- # Copyright (c) 2014 Michael Berkovich, tr8nhub.com
3
+ # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
3
4
  #
4
5
  # Permission is hereby granted, free of charge, to any person obtaining
5
6
  # a copy of this software and associated documentation files (the
@@ -44,9 +45,9 @@ class Tr8n::Tokens::Method < Tr8n::Tokens::Data
44
45
  end
45
46
 
46
47
  def substitute(label, context, language, options = {})
47
- object = hash_value(context, object_name)
48
+ object = Tr8n::Utils.hash_value(context, object_name)
48
49
  raise Tr8n::Exception.new("Missing value for a token: #{full_name}") unless object
49
- object_value = sanitize(object, object.send(object_method_name), options.merge(:sanitize_values => true), language)
50
+ object_value = sanitize(object.send(object_method_name), object, language, options.merge(:safe => false))
50
51
  label.gsub(full_name, object_value)
51
52
  end
52
53
  end
@@ -1,5 +1,6 @@
1
+ # encoding: UTF-8
1
2
  #--
2
- # Copyright (c) 2014 Michael Berkovich, tr8nhub.com
3
+ # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
3
4
  #
4
5
  # Permission is hereby granted, free of charge, to any person obtaining
5
6
  # a copy of this software and associated documentation files (the
@@ -72,6 +73,13 @@ class Tr8n::Tokens::Transform < Tr8n::Tokens::Data
72
73
  not displayed_in_translation?
73
74
  end
74
75
 
76
+ def prepare_label_for_suggestion(label, index, language)
77
+ context = context_for_language(language)
78
+ values = generate_value_map(piped_params, context)
79
+
80
+ label.gsub(full_name, values[context.default_rule] || values.values.first)
81
+ end
82
+
75
83
  # token: {count|| one: message, many: messages}
76
84
  # results in: {"one": "message", "many": "messages"}
77
85
  #
@@ -90,7 +98,7 @@ class Tr8n::Tokens::Transform < Tr8n::Tokens::Data
90
98
  # token: {actors:|| likes, like}
91
99
  # transform: ["unsupported", {"one": "{$0}", "other": "{$1}"}]
92
100
  # results in: {"one": "likes", "other": "like"}
93
- def generate_value_map(object, params, context)
101
+ def generate_value_map(params, context)
94
102
  values = {}
95
103
 
96
104
  if params.first.index(':')
@@ -137,13 +145,13 @@ class Tr8n::Tokens::Transform < Tr8n::Tokens::Data
137
145
 
138
146
  # apply settings cases
139
147
  value = params[index]
140
- if Tr8n.session.application.feature_enabled?(:language_cases)
148
+ if language_cases_enabled?
141
149
  parts[1..-1].each do |case_key|
142
- lcase = context.language.language_case_by_keyword(case_key)
150
+ lcase = context.language.case_by_keyword(case_key)
143
151
  unless lcase
144
152
  raise Tr8n::Exception.new("Language case #{case_key} for context #{context.keyword} is not defined: #{full_name}")
145
153
  end
146
- value = lcase.apply(value, object)
154
+ value = lcase.apply(value)
147
155
  end
148
156
  end
149
157
  values[key] = values[key].gsub(token, value)
@@ -154,19 +162,21 @@ class Tr8n::Tokens::Transform < Tr8n::Tokens::Data
154
162
  end
155
163
 
156
164
  def substitute(label, context, language, options = {})
157
- object = Tr8n::Tokens::Data.token_object(context, key)
165
+ object = self.class.token_object(context, key)
158
166
 
159
167
  unless object
160
- raise Tr8n::Exception.new("Missing value for a token: #{full_name}")
168
+ Tr8n::Logger.error("Missing value for a token \"#{key}\" in \"#{label}\"")
169
+ return label
161
170
  end
162
171
 
163
172
  if piped_params.empty?
164
- raise Tr8n::Exception.new("Piped params may not be empty: #{full_name}")
173
+ Tr8n::Logger.error("Piped params may not be empty for token \"#{key}\" in \"#{label}\"")
174
+ return label
165
175
  end
166
176
 
167
177
  language_context = context_for_language(language)
168
178
 
169
- piped_values = generate_value_map(object, piped_params, language_context)
179
+ piped_values = generate_value_map(piped_params, language_context)
170
180
 
171
181
  rule = language_context.find_matching_rule(object)
172
182
  return label unless rule
@@ -180,8 +190,10 @@ class Tr8n::Tokens::Transform < Tr8n::Tokens::Data
180
190
 
181
191
  substitution_value = []
182
192
  if displayed_in_translation?
183
- substitution_value << token_value(hash_value(context, key), options, language)
193
+ substitution_value << token_value(Tr8n::Utils.hash_value(context, key), language, options)
184
194
  substitution_value << " "
195
+ else
196
+ value = value.gsub("##{short_name}#", token_value(Tr8n::Utils.hash_value(context, key), language, options))
185
197
  end
186
198
  substitution_value << value
187
199
 
@@ -1,5 +1,6 @@
1
+ # encoding: UTF-8
1
2
  #--
2
- # Copyright (c) 2014 Michael Berkovich, tr8nhub.com
3
+ # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
3
4
  #
4
5
  # Permission is hereby granted, free of charge, to any person obtaining
5
6
  # a copy of this software and associated documentation files (the
@@ -52,6 +53,7 @@ class Tr8n::Translation < Tr8n::Base
52
53
  #
53
54
  # 0 indicates the highest precedence
54
55
  #
56
+ # deprecated - this is now done by the service
55
57
  def calculate_precedence
56
58
  self.precedence = 0
57
59
  return unless has_context_rules?
@@ -63,15 +65,11 @@ class Tr8n::Translation < Tr8n::Base
63
65
  end
64
66
  end
65
67
 
68
+ # checks if the translation is valid for the given tokens
66
69
  #{
67
- # "count" => [{"type" => "number", "key" => "one"}],
68
- # "user" => ["type" => "gender", "key" => "male"]
69
- #}
70
- #{
71
- # "count" => [{"number":"one"}],
72
- # "user" => [{"gender":"male"}]
70
+ # "count" => {"number":"one"},
71
+ # "user" => {"gender":"male"}
73
72
  #}
74
- # checks if the translation is valid for the given tokens
75
73
  def matches_rules?(token_values)
76
74
  return true unless has_context_rules?
77
75
 
@@ -1,5 +1,6 @@
1
+ # encoding: UTF-8
1
2
  #--
2
- # Copyright (c) 2014 Michael Berkovich, tr8nhub.com
3
+ # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
3
4
  #
4
5
  # Permission is hereby granted, free of charge, to any person obtaining
5
6
  # a copy of this software and associated documentation files (the
@@ -32,8 +33,8 @@ class Tr8n::TranslationKey < Tr8n::Base
32
33
  super
33
34
 
34
35
  self.attributes[:key] ||= self.class.generate_key(label, description)
35
- self.attributes[:locale] ||= Tr8n.session.block_options[:locale] || application.default_locale
36
- self.attributes[:language] ||= application.language(locale)
36
+ self.attributes[:locale] ||= Tr8n.session.block_options[:locale] || (application ? application.default_locale : Tr8n.config.default_locale)
37
+ self.attributes[:language] ||= application ? application.language(locale) : Tr8n.config.default_language
37
38
  self.attributes[:translations] = {}
38
39
 
39
40
  if hash_value(attrs, :translations)
@@ -169,14 +170,15 @@ class Tr8n::TranslationKey < Tr8n::Base
169
170
  end
170
171
 
171
172
  def substitute_tokens(translated_label, token_values, language, options = {})
172
- if translated_label.index('{')
173
- dt = Tr8n::Tokens::DataTokenizer.new(translated_label, token_values, :allowed_tokens => data_tokens_names_map)
174
- translated_label = dt.substitute(language, options)
173
+ if Tr8n::Tokens::DataTokenizer.required?(translated_label)
174
+ translated_label = Tr8n::Tokens::DataTokenizer.new(translated_label, token_values, :allowed_tokens => data_tokens_names_map).substitute(language, options)
175
175
  end
176
176
 
177
- return translated_label unless translated_label.index('[')
178
- dt = Tr8n::Tokens::DecorationTokenizer.new(translated_label, token_values, :allowed_tokens => decoration_tokens)
179
- dt.substitute
177
+ if Tr8n::Tokens::DecorationTokenizer.required?(translated_label)
178
+ translated_label = Tr8n::Tokens::DecorationTokenizer.new(translated_label, token_values, :allowed_tokens => decoration_tokens).substitute
179
+ end
180
+
181
+ translated_label
180
182
  end
181
183
 
182
184
  #######################################################################################################
@@ -1,5 +1,6 @@
1
+ # encoding: UTF-8
1
2
  #--
2
- # Copyright (c) 2014 Michael Berkovich, tr8nhub.com
3
+ # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
3
4
  #
4
5
  # Permission is hereby granted, free of charge, to any person obtaining
5
6
  # a copy of this software and associated documentation files (the
@@ -1,5 +1,6 @@
1
+ # encoding: UTF-8
1
2
  #--
2
- # Copyright (c) 2014 Michael Berkovich, tr8nhub.com
3
+ # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
3
4
  #
4
5
  # Permission is hereby granted, free of charge, to any person obtaining
5
6
  # a copy of this software and associated documentation files (the
@@ -53,6 +54,10 @@ module Tr8n
53
54
  (0..16).to_a.map{|a| rand(16).to_s(16)}.join
54
55
  end
55
56
 
57
+ def self.hash_value(hash, key)
58
+ hash[key.to_s] || hash[key.to_sym]
59
+ end
60
+
56
61
  def self.split_by_sentence(text)
57
62
  sentence_regex = /[^.!?\s][^.!?]*(?:[.!?](?![\'"]?\s|$)[^.!?]*)*[.!?]?[\'"]?(?=\s|$)/
58
63
 
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2014 Michael Berkovich, tr8nhub.com
2
+ # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2014 Michael Berkovich, tr8nhub.com
2
+ # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2014 Michael Berkovich, tr8nhub.com
2
+ # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2014 Michael Berkovich, tr8nhub.com
2
+ # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2014 Michael Berkovich, tr8nhub.com
2
+ # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2014 Michael Berkovich, tr8nhub.com
2
+ # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2014 Michael Berkovich, tr8nhub.com
2
+ # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2014 Michael Berkovich, tr8nhub.com
2
+ # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2014 Michael Berkovich, tr8nhub.com
2
+ # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2014 Michael Berkovich, tr8nhub.com
2
+ # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -0,0 +1,1362 @@
1
+ {"locale":"en-US",
2
+ "name":"English (US)",
3
+ "contexts":{
4
+ "date":{
5
+ "keyword":"date",
6
+ "keys":[
7
+ "past",
8
+ "present",
9
+ "future"
10
+ ],
11
+ "default_key":"present",
12
+ "token_expression":"/.*(date|time)(\\d)*$/",
13
+ "variables":[
14
+ "@date"
15
+ ],
16
+ "token_mapping":[
17
+ "unsupported",
18
+ "unsupported",
19
+ {
20
+ "past":"{$0}",
21
+ "present":"{$1}",
22
+ "future":"{$2}"
23
+ }
24
+ ],
25
+ "rules":{
26
+ "future":{
27
+ "keyword":"future",
28
+ "description":"{token} is in the past",
29
+ "conditions":"(< @date (today))",
30
+ "conditions_expression":[
31
+ "<",
32
+ "@date",
33
+ [
34
+ "today"
35
+ ]
36
+ ]
37
+ },
38
+ "past":{
39
+ "keyword":"past",
40
+ "description":"{token} is in the future",
41
+ "conditions":"(> @date (today))",
42
+ "conditions_expression":[
43
+ ">",
44
+ "@date",
45
+ [
46
+ "today"
47
+ ]
48
+ ]
49
+ },
50
+ "present":{
51
+ "keyword":"present",
52
+ "description":"{token} is in the present",
53
+ "conditions":"(= @date (today))",
54
+ "conditions_expression":[
55
+ "=",
56
+ "@date",
57
+ [
58
+ "today"
59
+ ]
60
+ ]
61
+ }
62
+ }
63
+ },
64
+ "gender":{
65
+ "keyword":"gender",
66
+ "keys":[
67
+ "male",
68
+ "female",
69
+ "other"
70
+ ],
71
+ "default_key":"other",
72
+ "token_expression":"/.*(user|translator|profile|actor|target)(\\d)*$/",
73
+ "variables":[
74
+ "@gender"
75
+ ],
76
+ "token_mapping":[
77
+ {
78
+ "other":"{$0}"
79
+ },
80
+ {
81
+ "male":"{$0}",
82
+ "female":"{$1}",
83
+ "other":"{$0}/{$1}"
84
+ },
85
+ {
86
+ "male":"{$0}",
87
+ "female":"{$1}",
88
+ "other":"{$2}"
89
+ }
90
+ ],
91
+ "rules":{
92
+ "male":{
93
+ "keyword":"male",
94
+ "description":"{token} is a male",
95
+ "conditions":"(= 'male' @gender)",
96
+ "conditions_expression":[
97
+ "=",
98
+ "male",
99
+ "@gender"
100
+ ]
101
+ },
102
+ "female":{
103
+ "keyword":"female",
104
+ "description":"{token} is a female",
105
+ "conditions":"(= 'female' @gender)",
106
+ "conditions_expression":[
107
+ "=",
108
+ "female",
109
+ "@gender"
110
+ ]
111
+ },
112
+ "other":{
113
+ "keyword":"other",
114
+ "description":"{token}'s gender is unknown"
115
+ }
116
+ }
117
+ },
118
+ "genders":{
119
+ "keyword":"genders",
120
+ "description":"",
121
+ "keys":[
122
+ "male",
123
+ "female",
124
+ "unknown",
125
+ "other"
126
+ ],
127
+ "default_key":"other",
128
+ "token_expression":"/.*(users|profiles|actors|targets)(\\d)*$/",
129
+ "variables":[
130
+ "@genders"
131
+ ],
132
+ "token_mapping":[
133
+ "unsupported",
134
+ {
135
+ "male":"{$0}",
136
+ "female":"{$0}",
137
+ "unknown":"{$1}",
138
+ "other":"{$1}"
139
+ },
140
+ {
141
+ "male":"{$0}",
142
+ "female":"{$1}",
143
+ "unknown":"{$1}",
144
+ "other":"{$2}"
145
+ },
146
+ {
147
+ "male":"{$0}",
148
+ "female":"{$1}",
149
+ "unknown":"{$2}",
150
+ "other":"{$3}"
151
+ }
152
+ ],
153
+ "rules":{
154
+ "male":{
155
+ "keyword":"male",
156
+ "description":"{token} contains 1 male",
157
+ "conditions":"(&& (= 1 (count @genders)) (all @genders 'male'))",
158
+ "conditions_expression":[
159
+ "&&",
160
+ [
161
+ "=",
162
+ 1,
163
+ [
164
+ "count",
165
+ "@genders"
166
+ ]
167
+ ],
168
+ [
169
+ "all",
170
+ "@genders",
171
+ "male"
172
+ ]
173
+ ]
174
+ },
175
+ "female":{
176
+ "keyword":"female",
177
+ "description":"{token} contains 1 female",
178
+ "conditions":"(&& (= 1 (count @genders)) (all @genders 'female'))",
179
+ "conditions_expression":[
180
+ "&&",
181
+ [
182
+ "=",
183
+ 1,
184
+ [
185
+ "count",
186
+ "@genders"
187
+ ]
188
+ ],
189
+ [
190
+ "all",
191
+ "@genders",
192
+ "female"
193
+ ]
194
+ ]
195
+ },
196
+ "unknown":{
197
+ "keyword":"unknown",
198
+ "description":"{token} contains 1 person with unknown gender",
199
+ "conditions":"(&& (= 1 (count @genders)) (all @genders 'unknown'))",
200
+ "conditions_expression":[
201
+ "&&",
202
+ [
203
+ "=",
204
+ 1,
205
+ [
206
+ "count",
207
+ "@genders"
208
+ ]
209
+ ],
210
+ [
211
+ "all",
212
+ "@genders",
213
+ "unknown"
214
+ ]
215
+ ]
216
+ },
217
+ "other":{
218
+ "keyword":"other",
219
+ "description":"{token} contains at least 2 people"
220
+ }
221
+ }
222
+ },
223
+ "list":{
224
+ "keyword":"list",
225
+ "keys":[
226
+ "one",
227
+ "other"
228
+ ],
229
+ "default_key":"other",
230
+ "token_expression":"/.*(items|list)(\\d)*$/",
231
+ "variables":[
232
+ "@count"
233
+ ],
234
+ "token_mapping":[
235
+ "unsupported",
236
+ {
237
+ "one":"{$0}",
238
+ "other":"{$1}"
239
+ }
240
+ ],
241
+ "rules":{
242
+ "one":{
243
+ "keyword":"one",
244
+ "description":"{token} contains 1 element",
245
+ "conditions":"(= 1 @count)",
246
+ "conditions_expression":[
247
+ "=",
248
+ 1,
249
+ "@count"
250
+ ]
251
+ },
252
+ "other":{
253
+ "keyword":"other",
254
+ "description":"{token} contains at least 2 elements"
255
+ }
256
+ }
257
+ },
258
+ "number":{
259
+ "keyword":"number",
260
+ "keys":[
261
+ "one",
262
+ "other"
263
+ ],
264
+ "default_key":"other",
265
+ "token_expression":"/.*(count|num|minutes|seconds|hours|sum|total)(\\d)*$/",
266
+ "variables":[
267
+ "@n"
268
+ ],
269
+ "token_mapping":[
270
+ {
271
+ "one":"{$0}",
272
+ "other":"{$0::plural}"
273
+ },
274
+ {
275
+ "one":"{$0}",
276
+ "other":"{$1}"
277
+ }
278
+ ],
279
+ "rules":{
280
+ "one":{
281
+ "keyword":"one",
282
+ "description":"{token} is 1",
283
+ "examples":"1",
284
+ "conditions":"(= @n 1)",
285
+ "conditions_expression":[
286
+ "=",
287
+ "@n",
288
+ 1
289
+ ]
290
+ },
291
+ "other":{
292
+ "keyword":"other",
293
+ "description":"{token} is not 1",
294
+ "examples":"0, 2-999; 1.2, 2.07..."
295
+ }
296
+ }
297
+ }
298
+ },
299
+ "cases":{
300
+ "plural":{
301
+ "keyword":"plural",
302
+ "latin_name":"Plural",
303
+ "description":"Converts singular form to plural",
304
+ "application":"phrase",
305
+ "rules":[
306
+ {
307
+ "description":"Uncountable word",
308
+ "conditions":"(in 'sheep,fish,series,species,money,rice,information,equipment' @value)",
309
+ "conditions_expression":[
310
+ "in",
311
+ "sheep,fish,series,species,money,rice,information,equipment",
312
+ "@value"
313
+ ],
314
+ "operations":"@value",
315
+ "operations_expression":"@value"
316
+ },
317
+ {
318
+ "description":"Irregular word",
319
+ "conditions":"(= 'move' @value)",
320
+ "conditions_expression":[
321
+ "=",
322
+ "move",
323
+ "@value"
324
+ ],
325
+ "operations":"(quote 'moves')",
326
+ "operations_expression":[
327
+ "quote",
328
+ "moves"
329
+ ]
330
+ },
331
+ {
332
+ "description":"Irregular word",
333
+ "conditions":"(= 'sex' @value)",
334
+ "conditions_expression":[
335
+ "=",
336
+ "sex",
337
+ "@value"
338
+ ],
339
+ "operations":"(quote 'sexes')",
340
+ "operations_expression":[
341
+ "quote",
342
+ "sexes"
343
+ ]
344
+ },
345
+ {
346
+ "description":"Irregular word",
347
+ "conditions":"(= 'child' @value)",
348
+ "conditions_expression":[
349
+ "=",
350
+ "child",
351
+ "@value"
352
+ ],
353
+ "operations":"(quote 'children')",
354
+ "operations_expression":[
355
+ "quote",
356
+ "children"
357
+ ]
358
+ },
359
+ {
360
+ "description":"Irregular word",
361
+ "conditions":"(= 'person' @value)",
362
+ "conditions_expression":[
363
+ "=",
364
+ "person",
365
+ "@value"
366
+ ],
367
+ "operations":"(quote 'people')",
368
+ "operations_expression":[
369
+ "quote",
370
+ "people"
371
+ ]
372
+ },
373
+ {
374
+ "conditions":"(match '/(quiz)$/i' @value)",
375
+ "conditions_expression":[
376
+ "match",
377
+ "/(quiz)$/i",
378
+ "@value"
379
+ ],
380
+ "operations":"(replace '/(quiz)$/i' '$1zes' @value)",
381
+ "operations_expression":[
382
+ "replace",
383
+ "/(quiz)$/i",
384
+ "$1zes",
385
+ "@value"
386
+ ]
387
+ },
388
+ {
389
+ "conditions":"(match '/^(ox)$/i' @value)",
390
+ "conditions_expression":[
391
+ "match",
392
+ "/^(ox)$/i",
393
+ "@value"
394
+ ],
395
+ "operations":"(replace '/^(ox)$/i' '$1en' @value)",
396
+ "operations_expression":[
397
+ "replace",
398
+ "/^(ox)$/i",
399
+ "$1en",
400
+ "@value"
401
+ ]
402
+ },
403
+ {
404
+ "conditions":"(match '/([m|l])ouse$/i' @value)",
405
+ "conditions_expression":[
406
+ "match",
407
+ "/([m|l])ouse$/i",
408
+ "@value"
409
+ ],
410
+ "operations":"(replace '/([m|l])ouse$/i' '$1ice' @value)",
411
+ "operations_expression":[
412
+ "replace",
413
+ "/([m|l])ouse$/i",
414
+ "$1ice",
415
+ "@value"
416
+ ]
417
+ },
418
+ {
419
+ "conditions":"(match '/(matr|vert|ind)ix|ex$/i' @value)",
420
+ "conditions_expression":[
421
+ "match",
422
+ "/(matr|vert|ind)ix|ex$/i",
423
+ "@value"
424
+ ],
425
+ "operations":"(replace '/(matr|vert|ind)ix|ex$/i' '$1ices' @value)",
426
+ "operations_expression":[
427
+ "replace",
428
+ "/(matr|vert|ind)ix|ex$/i",
429
+ "$1ices",
430
+ "@value"
431
+ ]
432
+ },
433
+ {
434
+ "conditions":"(match '/(x|ch|ss|sh)$/i' @value)",
435
+ "conditions_expression":[
436
+ "match",
437
+ "/(x|ch|ss|sh)$/i",
438
+ "@value"
439
+ ],
440
+ "operations":"(replace '/(x|ch|ss|sh)$/i' '$1es' @value)",
441
+ "operations_expression":[
442
+ "replace",
443
+ "/(x|ch|ss|sh)$/i",
444
+ "$1es",
445
+ "@value"
446
+ ]
447
+ },
448
+ {
449
+ "conditions":"(match '/([^aeiouy]|qu)y$/i' @value)",
450
+ "conditions_expression":[
451
+ "match",
452
+ "/([^aeiouy]|qu)y$/i",
453
+ "@value"
454
+ ],
455
+ "operations":"(replace '/([^aeiouy]|qu)y$/i' '$1ies' @value)",
456
+ "operations_expression":[
457
+ "replace",
458
+ "/([^aeiouy]|qu)y$/i",
459
+ "$1ies",
460
+ "@value"
461
+ ]
462
+ },
463
+ {
464
+ "conditions":"(match '/([^aeiouy]|qu)ies$/i' @value)",
465
+ "conditions_expression":[
466
+ "match",
467
+ "/([^aeiouy]|qu)ies$/i",
468
+ "@value"
469
+ ],
470
+ "operations":"(replace '/([^aeiouy]|qu)ies$/i' '$1y' @value)",
471
+ "operations_expression":[
472
+ "replace",
473
+ "/([^aeiouy]|qu)ies$/i",
474
+ "$1y",
475
+ "@value"
476
+ ]
477
+ },
478
+ {
479
+ "conditions":"(match '/(hive)$/i' @value)",
480
+ "conditions_expression":[
481
+ "match",
482
+ "/(hive)$/i",
483
+ "@value"
484
+ ],
485
+ "operations":"(replace '/(hive)$/i' '$1s' @value)",
486
+ "operations_expression":[
487
+ "replace",
488
+ "/(hive)$/i",
489
+ "$1s",
490
+ "@value"
491
+ ]
492
+ },
493
+ {
494
+ "conditions":"(match '/(?:([^f])fe|([lr])f)$/i' @value)",
495
+ "conditions_expression":[
496
+ "match",
497
+ "/(?:([^f])fe|([lr])f)$/i",
498
+ "@value"
499
+ ],
500
+ "operations":"(replace '/(?:([^f])fe|([lr])f)$/i' '$1$2ves' @value)",
501
+ "operations_expression":[
502
+ "replace",
503
+ "/(?:([^f])fe|([lr])f)$/i",
504
+ "$1$2ves",
505
+ "@value"
506
+ ]
507
+ },
508
+ {
509
+ "conditions":"(match '/sis$/i' @value)",
510
+ "conditions_expression":[
511
+ "match",
512
+ "/sis$/i",
513
+ "@value"
514
+ ],
515
+ "operations":"(replace '/sis$/i' 'ses' @value)",
516
+ "operations_expression":[
517
+ "replace",
518
+ "/sis$/i",
519
+ "ses",
520
+ "@value"
521
+ ]
522
+ },
523
+ {
524
+ "conditions":"(match '/([ti])um$/i' @value)",
525
+ "conditions_expression":[
526
+ "match",
527
+ "/([ti])um$/i",
528
+ "@value"
529
+ ],
530
+ "operations":"(replace '/([ti])um$/i' '$1a' @value)",
531
+ "operations_expression":[
532
+ "replace",
533
+ "/([ti])um$/i",
534
+ "$1a",
535
+ "@value"
536
+ ]
537
+ },
538
+ {
539
+ "conditions":"(match '/(buffal|tomat|potat)o$/i' @value)",
540
+ "conditions_expression":[
541
+ "match",
542
+ "/(buffal|tomat|potat)o$/i",
543
+ "@value"
544
+ ],
545
+ "operations":"(replace '/(buffal|tomat|potat)o$/i' '$1oes' @value)",
546
+ "operations_expression":[
547
+ "replace",
548
+ "/(buffal|tomat|potat)o$/i",
549
+ "$1oes",
550
+ "@value"
551
+ ]
552
+ },
553
+ {
554
+ "conditions":"(match '/(bu)s$/i' @value)",
555
+ "conditions_expression":[
556
+ "match",
557
+ "/(bu)s$/i",
558
+ "@value"
559
+ ],
560
+ "operations":"(replace '/(bu)s$/i' '$1ses' @value)",
561
+ "operations_expression":[
562
+ "replace",
563
+ "/(bu)s$/i",
564
+ "$1ses",
565
+ "@value"
566
+ ]
567
+ },
568
+ {
569
+ "conditions":"(match '/(alias|status)$/i' @value)",
570
+ "conditions_expression":[
571
+ "match",
572
+ "/(alias|status)$/i",
573
+ "@value"
574
+ ],
575
+ "operations":"(replace '/(alias|status)$/i' '$1es' @value)",
576
+ "operations_expression":[
577
+ "replace",
578
+ "/(alias|status)$/i",
579
+ "$1es",
580
+ "@value"
581
+ ]
582
+ },
583
+ {
584
+ "conditions":"(match '/(octop)us$/i' @value)",
585
+ "conditions_expression":[
586
+ "match",
587
+ "/(octop)us$/i",
588
+ "@value"
589
+ ],
590
+ "operations":"(replace '/(octop)us$/i' '$1i' @value)",
591
+ "operations_expression":[
592
+ "replace",
593
+ "/(octop)us$/i",
594
+ "$1i",
595
+ "@value"
596
+ ]
597
+ },
598
+ {
599
+ "conditions":"(match '/(ax|test)is$/i' @value)",
600
+ "conditions_expression":[
601
+ "match",
602
+ "/(ax|test)is$/i",
603
+ "@value"
604
+ ],
605
+ "operations":"(replace '/(ax|test)is$/i' '$1es' @value)",
606
+ "operations_expression":[
607
+ "replace",
608
+ "/(ax|test)is$/i",
609
+ "$1es",
610
+ "@value"
611
+ ]
612
+ },
613
+ {
614
+ "conditions":"(match '/us$/i' @value)",
615
+ "conditions_expression":[
616
+ "match",
617
+ "/us$/i",
618
+ "@value"
619
+ ],
620
+ "operations":"(replace '/us$/i' '$1es' @value)",
621
+ "operations_expression":[
622
+ "replace",
623
+ "/us$/i",
624
+ "$1es",
625
+ "@value"
626
+ ]
627
+ },
628
+ {
629
+ "conditions":"(match '/s$/i' @value)",
630
+ "conditions_expression":[
631
+ "match",
632
+ "/s$/i",
633
+ "@value"
634
+ ],
635
+ "operations":"(replace '/s$/i' 's' @value)",
636
+ "operations_expression":[
637
+ "replace",
638
+ "/s$/i",
639
+ "s",
640
+ "@value"
641
+ ]
642
+ },
643
+ {
644
+ "conditions":"(match '/$/' @value)",
645
+ "conditions_expression":[
646
+ "match",
647
+ "/$/",
648
+ "@value"
649
+ ],
650
+ "operations":"(replace '/$/' 's' @value)",
651
+ "operations_expression":[
652
+ "replace",
653
+ "/$/",
654
+ "s",
655
+ "@value"
656
+ ]
657
+ }
658
+ ]
659
+ },
660
+ "singular":{
661
+ "keyword":"singular",
662
+ "latin_name":"Singular",
663
+ "description":"Converts plural form to singular",
664
+ "application":"phrase",
665
+ "rules":[
666
+ {
667
+ "description":"Uncountable word",
668
+ "conditions":"(in 'sheep,fish,series,species,money,rice,information,equipment' @value)",
669
+ "conditions_expression":[
670
+ "in",
671
+ "sheep,fish,series,species,money,rice,information,equipment",
672
+ "@value"
673
+ ],
674
+ "operations":"@value",
675
+ "operations_expression":"@value"
676
+ },
677
+ {
678
+ "description":"Irregular word",
679
+ "conditions":"(= 'moves' @value)",
680
+ "conditions_expression":[
681
+ "=",
682
+ "moves",
683
+ "@value"
684
+ ],
685
+ "operations":"(quote 'move')",
686
+ "operations_expression":[
687
+ "quote",
688
+ "move"
689
+ ]
690
+ },
691
+ {
692
+ "description":"Irregular word",
693
+ "conditions":"(= 'sexes' @value)",
694
+ "conditions_expression":[
695
+ "=",
696
+ "sexes",
697
+ "@value"
698
+ ],
699
+ "operations":"(quote 'sex')",
700
+ "operations_expression":[
701
+ "quote",
702
+ "sex"
703
+ ]
704
+ },
705
+ {
706
+ "description":"Irregular word",
707
+ "conditions":"(= 'children' @value)",
708
+ "conditions_expression":[
709
+ "=",
710
+ "children",
711
+ "@value"
712
+ ],
713
+ "operations":"(quote 'child')",
714
+ "operations_expression":[
715
+ "quote",
716
+ "child"
717
+ ]
718
+ },
719
+ {
720
+ "description":"Irregular word",
721
+ "conditions":"(= 'people' @value)",
722
+ "conditions_expression":[
723
+ "=",
724
+ "people",
725
+ "@value"
726
+ ],
727
+ "operations":"(quote 'person')",
728
+ "operations_expression":[
729
+ "quote",
730
+ "person"
731
+ ]
732
+ },
733
+ {
734
+ "conditions":"(match '/(n)ews$/i' @value)",
735
+ "conditions_expression":[
736
+ "match",
737
+ "/(n)ews$/i",
738
+ "@value"
739
+ ],
740
+ "operations":"(replace '/(n)ews$/i' '$1ews' @value)",
741
+ "operations_expression":[
742
+ "replace",
743
+ "/(n)ews$/i",
744
+ "$1ews",
745
+ "@value"
746
+ ]
747
+ },
748
+ {
749
+ "conditions":"(match '/([ti])a$/i' @value)",
750
+ "conditions_expression":[
751
+ "match",
752
+ "/([ti])a$/i",
753
+ "@value"
754
+ ],
755
+ "operations":"(replace '/([ti])a$/i' '$1um' @value)",
756
+ "operations_expression":[
757
+ "replace",
758
+ "/([ti])a$/i",
759
+ "$1um",
760
+ "@value"
761
+ ]
762
+ },
763
+ {
764
+ "conditions":"(match '/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' @value)",
765
+ "conditions_expression":[
766
+ "match",
767
+ "/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i",
768
+ "@value"
769
+ ],
770
+ "operations":"(replace '/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' '$1$2sis' @value)",
771
+ "operations_expression":[
772
+ "replace",
773
+ "/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i",
774
+ "$1$2sis",
775
+ "@value"
776
+ ]
777
+ },
778
+ {
779
+ "conditions":"(match '/(^analy)ses$/i' @value)",
780
+ "conditions_expression":[
781
+ "match",
782
+ "/(^analy)ses$/i",
783
+ "@value"
784
+ ],
785
+ "operations":"(replace '/(^analy)ses$/i' '$1sis' @value)",
786
+ "operations_expression":[
787
+ "replace",
788
+ "/(^analy)ses$/i",
789
+ "$1sis",
790
+ "@value"
791
+ ]
792
+ },
793
+ {
794
+ "conditions":"(match '/([^f])ves$/i' @value)",
795
+ "conditions_expression":[
796
+ "match",
797
+ "/([^f])ves$/i",
798
+ "@value"
799
+ ],
800
+ "operations":"(replace '/([^f])ves$/i' '$1fe' @value)",
801
+ "operations_expression":[
802
+ "replace",
803
+ "/([^f])ves$/i",
804
+ "$1fe",
805
+ "@value"
806
+ ]
807
+ },
808
+ {
809
+ "conditions":"(match '/(hive)s$/i' @value)",
810
+ "conditions_expression":[
811
+ "match",
812
+ "/(hive)s$/i",
813
+ "@value"
814
+ ],
815
+ "operations":"(replace '/(hive)s$/i' '$1' @value)",
816
+ "operations_expression":[
817
+ "replace",
818
+ "/(hive)s$/i",
819
+ "$1",
820
+ "@value"
821
+ ]
822
+ },
823
+ {
824
+ "conditions":"(match '/(tive)s$/i' @value)",
825
+ "conditions_expression":[
826
+ "match",
827
+ "/(tive)s$/i",
828
+ "@value"
829
+ ],
830
+ "operations":"(replace '/(tive)s$/i' '$1' @value)",
831
+ "operations_expression":[
832
+ "replace",
833
+ "/(tive)s$/i",
834
+ "$1",
835
+ "@value"
836
+ ]
837
+ },
838
+ {
839
+ "conditions":"(match '/([lr])ves$/i' @value)",
840
+ "conditions_expression":[
841
+ "match",
842
+ "/([lr])ves$/i",
843
+ "@value"
844
+ ],
845
+ "operations":"(replace '/([lr])ves$/i' '$1f' @value)",
846
+ "operations_expression":[
847
+ "replace",
848
+ "/([lr])ves$/i",
849
+ "$1f",
850
+ "@value"
851
+ ]
852
+ },
853
+ {
854
+ "conditions":"(match '/([^aeiouy]|qu)ies$/i' @value)",
855
+ "conditions_expression":[
856
+ "match",
857
+ "/([^aeiouy]|qu)ies$/i",
858
+ "@value"
859
+ ],
860
+ "operations":"(replace '/([^aeiouy]|qu)ies$/i' '$1y' @value)",
861
+ "operations_expression":[
862
+ "replace",
863
+ "/([^aeiouy]|qu)ies$/i",
864
+ "$1y",
865
+ "@value"
866
+ ]
867
+ },
868
+ {
869
+ "conditions":"(match '/(s)eries$/i' @value)",
870
+ "conditions_expression":[
871
+ "match",
872
+ "/(s)eries$/i",
873
+ "@value"
874
+ ],
875
+ "operations":"(replace '/(s)eries$/i' '$1eries' @value)",
876
+ "operations_expression":[
877
+ "replace",
878
+ "/(s)eries$/i",
879
+ "$1eries",
880
+ "@value"
881
+ ]
882
+ },
883
+ {
884
+ "conditions":"(match '/(m)ovies$/i' @value)",
885
+ "conditions_expression":[
886
+ "match",
887
+ "/(m)ovies$/i",
888
+ "@value"
889
+ ],
890
+ "operations":"(replace '/(m)ovies$/i' '$1ovie' @value)",
891
+ "operations_expression":[
892
+ "replace",
893
+ "/(m)ovies$/i",
894
+ "$1ovie",
895
+ "@value"
896
+ ]
897
+ },
898
+ {
899
+ "conditions":"(match '/(x|ch|ss|sh)es$/i' @value)",
900
+ "conditions_expression":[
901
+ "match",
902
+ "/(x|ch|ss|sh)es$/i",
903
+ "@value"
904
+ ],
905
+ "operations":"(replace '/(x|ch|ss|sh)es$/i' '$1' @value)",
906
+ "operations_expression":[
907
+ "replace",
908
+ "/(x|ch|ss|sh)es$/i",
909
+ "$1",
910
+ "@value"
911
+ ]
912
+ },
913
+ {
914
+ "conditions":"(match '/([m|l])ice$/i' @value)",
915
+ "conditions_expression":[
916
+ "match",
917
+ "/([m|l])ice$/i",
918
+ "@value"
919
+ ],
920
+ "operations":"(replace '/([m|l])ice$/i' '$1ouse' @value)",
921
+ "operations_expression":[
922
+ "replace",
923
+ "/([m|l])ice$/i",
924
+ "$1ouse",
925
+ "@value"
926
+ ]
927
+ },
928
+ {
929
+ "conditions":"(match '/(bus)es$/i' @value)",
930
+ "conditions_expression":[
931
+ "match",
932
+ "/(bus)es$/i",
933
+ "@value"
934
+ ],
935
+ "operations":"(replace '/(bus)es$/i' '$1' @value)",
936
+ "operations_expression":[
937
+ "replace",
938
+ "/(bus)es$/i",
939
+ "$1",
940
+ "@value"
941
+ ]
942
+ },
943
+ {
944
+ "conditions":"(match '/(o)es$/i' @value)",
945
+ "conditions_expression":[
946
+ "match",
947
+ "/(o)es$/i",
948
+ "@value"
949
+ ],
950
+ "operations":"(replace '/(o)es$/i' '$1' @value)",
951
+ "operations_expression":[
952
+ "replace",
953
+ "/(o)es$/i",
954
+ "$1",
955
+ "@value"
956
+ ]
957
+ },
958
+ {
959
+ "conditions":"(match '/(shoe)s$/i' @value)",
960
+ "conditions_expression":[
961
+ "match",
962
+ "/(shoe)s$/i",
963
+ "@value"
964
+ ],
965
+ "operations":"(replace '/(shoe)s$/i' '$1' @value)",
966
+ "operations_expression":[
967
+ "replace",
968
+ "/(shoe)s$/i",
969
+ "$1",
970
+ "@value"
971
+ ]
972
+ },
973
+ {
974
+ "conditions":"(match '/(cris|ax|test)es$/i' @value)",
975
+ "conditions_expression":[
976
+ "match",
977
+ "/(cris|ax|test)es$/i",
978
+ "@value"
979
+ ],
980
+ "operations":"(replace '/(cris|ax|test)es$/i' '$1is' @value)",
981
+ "operations_expression":[
982
+ "replace",
983
+ "/(cris|ax|test)es$/i",
984
+ "$1is",
985
+ "@value"
986
+ ]
987
+ },
988
+ {
989
+ "conditions":"(match '/(octop|vir)i$/i' @value)",
990
+ "conditions_expression":[
991
+ "match",
992
+ "/(octop|vir)i$/i",
993
+ "@value"
994
+ ],
995
+ "operations":"(replace '/(octop|vir)i$/i' '$1us' @value)",
996
+ "operations_expression":[
997
+ "replace",
998
+ "/(octop|vir)i$/i",
999
+ "$1us",
1000
+ "@value"
1001
+ ]
1002
+ },
1003
+ {
1004
+ "conditions":"(match '/(alias|status)es$/i' @value)",
1005
+ "conditions_expression":[
1006
+ "match",
1007
+ "/(alias|status)es$/i",
1008
+ "@value"
1009
+ ],
1010
+ "operations":"(replace '/(alias|status)es$/i' '$1' @value)",
1011
+ "operations_expression":[
1012
+ "replace",
1013
+ "/(alias|status)es$/i",
1014
+ "$1",
1015
+ "@value"
1016
+ ]
1017
+ },
1018
+ {
1019
+ "conditions":"(match '/^(ox)en$/i' @value)",
1020
+ "conditions_expression":[
1021
+ "match",
1022
+ "/^(ox)en$/i",
1023
+ "@value"
1024
+ ],
1025
+ "operations":"(replace '/^(ox)en$/i' '$1' @value)",
1026
+ "operations_expression":[
1027
+ "replace",
1028
+ "/^(ox)en$/i",
1029
+ "$1",
1030
+ "@value"
1031
+ ]
1032
+ },
1033
+ {
1034
+ "conditions":"(match '/(vert|ind)ices$/i' @value)",
1035
+ "conditions_expression":[
1036
+ "match",
1037
+ "/(vert|ind)ices$/i",
1038
+ "@value"
1039
+ ],
1040
+ "operations":"(replace '/(vert|ind)ices$/i' '$1ex' @value)",
1041
+ "operations_expression":[
1042
+ "replace",
1043
+ "/(vert|ind)ices$/i",
1044
+ "$1ex",
1045
+ "@value"
1046
+ ]
1047
+ },
1048
+ {
1049
+ "conditions":"(match '/(matr)ices$/i' @value)",
1050
+ "conditions_expression":[
1051
+ "match",
1052
+ "/(matr)ices$/i",
1053
+ "@value"
1054
+ ],
1055
+ "operations":"(replace '/(matr)ices$/i' '$1ix' @value)",
1056
+ "operations_expression":[
1057
+ "replace",
1058
+ "/(matr)ices$/i",
1059
+ "$1ix",
1060
+ "@value"
1061
+ ]
1062
+ },
1063
+ {
1064
+ "conditions":"(match '/(quiz)zes$/i' @value)",
1065
+ "conditions_expression":[
1066
+ "match",
1067
+ "/(quiz)zes$/i",
1068
+ "@value"
1069
+ ],
1070
+ "operations":"(replace '/(quiz)zes$/i' '$1' @value)",
1071
+ "operations_expression":[
1072
+ "replace",
1073
+ "/(quiz)zes$/i",
1074
+ "$1",
1075
+ "@value"
1076
+ ]
1077
+ },
1078
+ {
1079
+ "conditions":"(match '/(us)es$/i' @value)",
1080
+ "conditions_expression":[
1081
+ "match",
1082
+ "/(us)es$/i",
1083
+ "@value"
1084
+ ],
1085
+ "operations":"(replace '/(us)es$/i' '$1' @value)",
1086
+ "operations_expression":[
1087
+ "replace",
1088
+ "/(us)es$/i",
1089
+ "$1",
1090
+ "@value"
1091
+ ]
1092
+ },
1093
+ {
1094
+ "conditions":"(match '/s$/i' @value)",
1095
+ "conditions_expression":[
1096
+ "match",
1097
+ "/s$/i",
1098
+ "@value"
1099
+ ],
1100
+ "operations":"(replace '/s$/i' '' @value)",
1101
+ "operations_expression":[
1102
+ "replace",
1103
+ "/s$/i",
1104
+ "",
1105
+ "@value"
1106
+ ]
1107
+ }
1108
+ ]
1109
+ },
1110
+ "pos":{
1111
+ "keyword":"pos",
1112
+ "latin_name":"Possessive",
1113
+ "description":"Used to indicate possession (i.e., ownership). It is usually created by adding 's to the word",
1114
+ "application":"phrase",
1115
+ "rules":[
1116
+ {
1117
+ "description":"if value ends in s, append '",
1118
+ "conditions":"(match '/s$/' @value)",
1119
+ "conditions_expression":[
1120
+ "match",
1121
+ "/s$/",
1122
+ "@value"
1123
+ ],
1124
+ "operations":"(append \"'\" @value)",
1125
+ "operations_expression":[
1126
+ "append",
1127
+ "'",
1128
+ "@value"
1129
+ ]
1130
+ },
1131
+ {
1132
+ "description":"in all other cases, append 's",
1133
+ "conditions":"(true)",
1134
+ "conditions_expression":[
1135
+ "true"
1136
+ ],
1137
+ "operations":"(append \"'s\" @value)",
1138
+ "operations_expression":[
1139
+ "append",
1140
+ "'s",
1141
+ "@value"
1142
+ ]
1143
+ }
1144
+ ]
1145
+ },
1146
+ "ord":{
1147
+ "keyword":"ord",
1148
+ "latin_name":"Ordinal",
1149
+ "native_name":"Short Ordinal",
1150
+ "description":"The adjective form of the cardinal numbers",
1151
+ "application":"phrase",
1152
+ "rules":[
1153
+ {
1154
+ "id":727,
1155
+ "description":"append 'st' if value ends in 1, but not in 11",
1156
+ "examples":"1, 21, 31, 41, 101, 121...",
1157
+ "conditions":"(&& (match '/1$/' @value) (! (match '/11$/' @value)))",
1158
+ "conditions_expression":[
1159
+ "&&",
1160
+ [
1161
+ "match",
1162
+ "/1$/",
1163
+ "@value"
1164
+ ],
1165
+ [
1166
+ "!",
1167
+ [
1168
+ "match",
1169
+ "/11$/",
1170
+ "@value"
1171
+ ]
1172
+ ]
1173
+ ],
1174
+ "operations":"(append 'st' @value)",
1175
+ "operations_expression":[
1176
+ "append",
1177
+ "st",
1178
+ "@value"
1179
+ ]
1180
+ },
1181
+ {
1182
+ "description":"append 'nd' if value ends in 2, but not in 12",
1183
+ "examples":"2, 22, 32, 42, 102, 122...",
1184
+ "conditions":"(&& (match '/2$/' @value) (! (match '/12$/' @value)))",
1185
+ "conditions_expression":[
1186
+ "&&",
1187
+ [
1188
+ "match",
1189
+ "/2$/",
1190
+ "@value"
1191
+ ],
1192
+ [
1193
+ "!",
1194
+ [
1195
+ "match",
1196
+ "/12$/",
1197
+ "@value"
1198
+ ]
1199
+ ]
1200
+ ],
1201
+ "operations":"(append 'nd' @value)",
1202
+ "operations_expression":[
1203
+ "append",
1204
+ "nd",
1205
+ "@value"
1206
+ ]
1207
+ },
1208
+ {
1209
+ "description":"append 'nd' if value ends in 3, but not in 13",
1210
+ "examples":"3, 23, 33, 43, 103, 123...",
1211
+ "conditions":"(&& (match '/3$/' @value) (! (match '/13$/' @value)))",
1212
+ "conditions_expression":[
1213
+ "&&",
1214
+ [
1215
+ "match",
1216
+ "/3$/",
1217
+ "@value"
1218
+ ],
1219
+ [
1220
+ "!",
1221
+ [
1222
+ "match",
1223
+ "/13$/",
1224
+ "@value"
1225
+ ]
1226
+ ]
1227
+ ],
1228
+ "operations":"(append 'rd' @value)",
1229
+ "operations_expression":[
1230
+ "append",
1231
+ "rd",
1232
+ "@value"
1233
+ ]
1234
+ },
1235
+ {
1236
+ "description":"append 'th' in all other cases",
1237
+ "examples":"0, 4, 5, 6, 7, 8, 9, 11, 12, 13, 111, 113...",
1238
+ "conditions":"(true)",
1239
+ "conditions_expression":[
1240
+ "true"
1241
+ ],
1242
+ "operations":"(append 'th' @value)",
1243
+ "operations_expression":[
1244
+ "append",
1245
+ "th",
1246
+ "@value"
1247
+ ]
1248
+ }
1249
+ ]
1250
+ },
1251
+ "ordinal":{
1252
+ "keyword":"ordinal",
1253
+ "latin_name":"Ordinal",
1254
+ "native_name":"Full Ordinal",
1255
+ "description":"The adjective form of the cardinal numbers",
1256
+ "application":"phrase",
1257
+ "rules":[
1258
+ {
1259
+ "description":"replace 1 with 'first'",
1260
+ "conditions":"(= 1 @value)",
1261
+ "conditions_expression":[
1262
+ "=",
1263
+ 1,
1264
+ "@value"
1265
+ ],
1266
+ "operations":"(replace 1 'first' @value)",
1267
+ "operations_expression":[
1268
+ "replace",
1269
+ 1,
1270
+ "first",
1271
+ "@value"
1272
+ ]
1273
+ },
1274
+ {
1275
+ "description":"replace 2 with 'second'",
1276
+ "conditions":"(= 2 @value)",
1277
+ "conditions_expression":[
1278
+ "=",
1279
+ 2,
1280
+ "@value"
1281
+ ],
1282
+ "operations":"(replace 2 'first' @value)",
1283
+ "operations_expression":[
1284
+ "replace",
1285
+ 2,
1286
+ "first",
1287
+ "@value"
1288
+ ]
1289
+ },
1290
+ {
1291
+ "description":"replace 3 with 'third'",
1292
+ "conditions":"(= 3 @value)",
1293
+ "conditions_expression":[
1294
+ "=",
1295
+ 3,
1296
+ "@value"
1297
+ ],
1298
+ "operations":"(replace 3 'third' @value)",
1299
+ "operations_expression":[
1300
+ "replace",
1301
+ 3,
1302
+ "third",
1303
+ "@value"
1304
+ ]
1305
+ }
1306
+ ]
1307
+ },
1308
+ "times":{
1309
+ "keyword":"times",
1310
+ "latin_name":"Iteration",
1311
+ "description":"The iteration form of the cardinal numbers",
1312
+ "application":"phrase",
1313
+ "rules":[
1314
+ {
1315
+ "description":"replace '1' with 'once'",
1316
+ "conditions":"(= 1 @value)",
1317
+ "conditions_expression":[
1318
+ "=",
1319
+ 1,
1320
+ "@value"
1321
+ ],
1322
+ "operations":"(replace '1' 'once' @value)",
1323
+ "operations_expression":[
1324
+ "replace",
1325
+ "1",
1326
+ "once",
1327
+ "@value"
1328
+ ]
1329
+ },
1330
+ {
1331
+ "description":"replace '2' with 'twice'",
1332
+ "conditions":"(= 2 @value)",
1333
+ "conditions_expression":[
1334
+ "=",
1335
+ 2,
1336
+ "@value"
1337
+ ],
1338
+ "operations":"(replace '2' 'twice' @value)",
1339
+ "operations_expression":[
1340
+ "replace",
1341
+ "2",
1342
+ "twice",
1343
+ "@value"
1344
+ ]
1345
+ },
1346
+ {
1347
+ "description":"in all other cases, append x times",
1348
+ "conditions":"(true)",
1349
+ "conditions_expression":[
1350
+ "true"
1351
+ ],
1352
+ "operations":"(append ' times' @value)",
1353
+ "operations_expression":[
1354
+ "append",
1355
+ " times",
1356
+ "@value"
1357
+ ]
1358
+ }
1359
+ ]
1360
+ }
1361
+ }
1362
+ }