improve globalized search queries: normalize input, fallbacks, etc

This commit is contained in:
Emi Matchu 2013-01-26 09:52:58 -06:00
parent 2798ebbd5c
commit e86bcfaf54

View file

@ -1,3 +1,6 @@
# encoding=utf-8
# ^ to put the regex in utf-8 mode
class Item class Item
module Search module Search
class Query class Query
@ -89,24 +92,37 @@ class Item
# Load the text query labels from I18n, so that when we see, say, # Load the text query labels from I18n, so that when we see, say,
# the filter "species:acara", we know it means species_support_id. # the filter "species:acara", we know it means species_support_id.
TEXT_KEYS_BY_LABEL = {} TEXT_KEYS_BY_LABEL = {}
IS_KEYWORDS = {}
OWNERSHIP_KEYWORDS = {} OWNERSHIP_KEYWORDS = {}
I18n.available_locales.each do |locale| I18n.available_locales.each do |locale|
TEXT_KEYS_BY_LABEL[locale] = {} TEXT_KEYS_BY_LABEL[locale] = {}
IS_KEYWORDS[locale] = Set.new
OWNERSHIP_KEYWORDS[locale] = {} OWNERSHIP_KEYWORDS[locale] = {}
I18n.fallbacks[locale].each do |fallback|
FIELD_CLASSES.keys.each do |key| FIELD_CLASSES.keys.each do |key|
# A locale can specify multiple labels for a key by separating by # A locale can specify multiple labels for a key by separating by
# commas: "occupies,zone,type" # commas: "occupies,zone,type"
labels = I18n.translate("items.search.labels.#{key}", labels = I18n.translate("items.search.labels.#{key}",
:locale => locale).split(',') :locale => fallback).split(',')
labels.each { |label| TEXT_KEYS_BY_LABEL[locale][label] = key }
labels.each do |label|
plain_label = label.parameterize # 'é' => 'e'
TEXT_KEYS_BY_LABEL[locale][plain_label] = key
end
is_keyword = I18n.translate('items.search.flag_keywords.is',
:locale => fallback)
IS_KEYWORDS[locale] << is_keyword.parameterize
{:owns => true, :wants => false}.each do |key, value| {:owns => true, :wants => false}.each do |key, value|
translated_key = I18n.translate("items.search.labels.user_#{key}", translated_key = I18n.translate("items.search.labels.user_#{key}",
:locale => locale) :locale => fallback)
OWNERSHIP_KEYWORDS[locale][translated_key] = value OWNERSHIP_KEYWORDS[locale][translated_key] = value
end end
end end
end end
end
TEXT_QUERY_RESOURCE_FINDERS = { TEXT_QUERY_RESOURCE_FINDERS = {
:species => lambda { |name| :species => lambda { |name|
@ -139,17 +155,22 @@ class Item
:user_closet_hanger_ownership => :ownership :user_closet_hanger_ownership => :ownership
} }
TEXT_FILTER_EXPR = /([+-]?)(?:([a-z]+):)?(?:"([^"]+)"|(\S+))/ TEXT_FILTER_EXPR = /([+-]?)(?:(\p{Word}+):)?(?:"([^"]+)"|(\S+))/
def self.from_text(text, user=nil) def self.from_text(text, user=nil)
filters = [] filters = []
is_keyword = I18n.translate('items.search.flag_keywords.is')
text.scan(TEXT_FILTER_EXPR) do |sign, label, quoted_value, unquoted_value| text.scan(TEXT_FILTER_EXPR) do |sign, label, quoted_value, unquoted_value|
label ||= 'name'
raw_value = quoted_value || unquoted_value raw_value = quoted_value || unquoted_value
is_positive = (sign != '-') is_positive = (sign != '-')
if label == is_keyword Rails.logger.debug(label.inspect)
Rails.logger.debug(TEXT_KEYS_BY_LABEL[I18n.locale].inspect)
Rails.logger.debug(IS_KEYWORDS[I18n.locale].inspect)
if label
plain_label = label.parameterize
if IS_KEYWORDS[I18n.locale].include?(plain_label)
# is-filters are weird. "-is:nc" is transposed to something more # is-filters are weird. "-is:nc" is transposed to something more
# like "-nc:<nil>", then it's translated into a negative "is_nc" # like "-nc:<nil>", then it's translated into a negative "is_nc"
# flag. Fun fact: "nc:foobar" and "-nc:foobar" also work. A bonus, # flag. Fun fact: "nc:foobar" and "-nc:foobar" also work. A bonus,
@ -157,10 +178,15 @@ class Item
# the unintended bonus syntax, but this is a darn good cheap # the unintended bonus syntax, but this is a darn good cheap
# technique for the time being. # technique for the time being.
label = raw_value label = raw_value
plain_label = raw_value.parameterize
raw_value = nil raw_value = nil
end end
key = TEXT_KEYS_BY_LABEL[I18n.locale][label] key = TEXT_KEYS_BY_LABEL[I18n.locale][plain_label]
else
key = :name
end
if key.nil? if key.nil?
message = I18n.translate('items.search.errors.not_found.label', message = I18n.translate('items.search.errors.not_found.label',
:label => label) :label => label)