tr8n_core 4.0.4 → 4.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }