Permalink
Browse files

Merge branch 'localization' of https://github.com/luan/chronic into l…

…uan-localization

Conflicts:
	lib/chronic/numerizer.rb
	lib/chronic/parser.rb
  • Loading branch information...
2 parents f90ab0c + bade124 commit 024943d417869613f801185b9221bffe8c6df219 @leejarvis leejarvis committed May 22, 2013
View
@@ -146,6 +146,19 @@ class to get full time zone support.
=> Thu, 15 Jun 2006 05:45:00 UTC +00:00
```
+## Localization
+
+Chronic supports basic localization. You can either create your own based on
+the default english locale or use the
+[chronic-l10n](http://github.com/luan/chronic-l10n) gem. You can change the
+locale by simply changing the `Chronic.locale` value, such as (given you have
+:pt-BR available):
+
+ >> Chronic.locale = :'pt-BR'
+ >> Chronic.parse("15 de Junho de 2006 as 5:45 da manha")
+ => Thu, 15 Jun 2006 05:45:00 UTC +00:00
+
+
## Limitations
Chronic uses Ruby's built in Time class for all time storage and computation.
View
@@ -53,7 +53,6 @@ module Chronic
VERSION = "0.9.1"
class << self
-
# Returns true when debug mode is enabled.
attr_accessor :debug
@@ -69,11 +68,33 @@ class << self
#
# Returns The Time class Chronic uses internally.
attr_accessor :time_class
+
+ # Returns the available locales that Chronic can use
+ attr_accessor :locale_hashes
+
+ # The current locale Chronic is using to parse strings
+ #
+ # Examples:
+ #
+ # require 'chronic'
+ #
+ # Chronic.locale = :'pt-BR'
+ # Chronic.parse('15 de Junho de 2006 as 5:54 da manha ')
+ # # => Thu, 15 Jun 2006 05:45:00 UTC +00:00
+ #
+ # Returns the locale name Chronic uses internally
+ attr_accessor :locale
end
self.debug = false
self.time_class = Time
+ self.locale = :en
+
+ require 'chronic/locales/en'
+ self.locale_hashes = {
+ :en => Chronic::Locales::EN
+ }
# Parses a string containing a natural language date or time.
#
@@ -84,9 +105,47 @@ class << self
# text - The String text to parse.
# opts - An optional Hash of configuration options passed to Parser::new.
def self.parse(text, options = {})
+ # ensure current locale is available
+ raise ArgumentError, "#{locale} is not an available locale" unless has_locale(locale)
+
Parser.new(options).parse(text)
end
+ # Adds a locale to the locale hash
+ #
+ # name - Symbol locale name
+ # locale - Hash locale values
+ def self.add_locale(name, locale)
+ raise ArgumentError, "Locale shoud be a hash" unless locale.is_a?(Hash)
+ locale_hashes[name] = locale
+ end
+
+ # Checks if a locale is available
+ #
+ # name - Symbol locale name
+ #
+ # Returns true if the locale is available, false if not
+ def self.has_locale(name)
+ locale_hashes.include? name
+ end
+
+
+ # Returns the translations for the current locale
+ def self.translate(keys, loc=nil)
+ loc ||= locale
+ node = locale_hashes[loc]
+
+ keys.each do |key|
+ if node.include? key
+ node = node[key]
+ else
+ return translate(keys, :en)
+ end
+ end
+
+ node
+ end
+
# Construct a new time object determining possible month overflows
# and leap years.
#
@@ -140,5 +199,4 @@ def self.construct(year, month = 1, day = 1, hour = 0, minute = 0, second = 0)
Chronic.time_class.local(year, month, day, hour, minute, second)
end
-
end
View
@@ -18,16 +18,11 @@ def self.scan(tokens, options)
#
# Returns a new Grabber object.
def self.scan_for_all(token)
- scan_for token, self,
- {
- /last/ => :last,
- /this/ => :this,
- /next/ => :next
- }
+ scan_for token, self, Chronic.translate([:grabber])
end
def to_s
'grabber-' << @type.to_s
end
end
-end
+end
View
@@ -0,0 +1,183 @@
+module Chronic
+ module Locales
+ EN = {
+ :pointer => {
+ /\bpast\b/ => :past,
+ /\b(?:future|in)\b/ => :future,
+ },
+ :ordinal_regex => /^(\d*)(st|nd|rd|th)$/,
+ :numerizer => {
+ :and => 'and',
+ :preprocess => [
+ [/ +|([^\d])-([^\d])/, '\1 \2'], # will mutilate hyphenated-words but shouldn't matter for date extraction
+ [/a half/, 'haAlf'] # take the 'a' out so it doesn't turn into a 1, save the half for the end
+ ],
+ :fractional => [
+ [/(\d+)(?: | and |-)*haAlf/i, proc { ($1.to_f + 0.5).to_s }]
+ ],
+ :direct_nums => [
+ ['eleven', '11'],
+ ['twelve', '12'],
+ ['thirteen', '13'],
+ ['fourteen', '14'],
+ ['fifteen', '15'],
+ ['sixteen', '16'],
+ ['seventeen', '17'],
+ ['eighteen', '18'],
+ ['nineteen', '19'],
+ ['ninteen', '19'], # Common mis-spelling
+ ['zero', '0'],
+ ['one', '1'],
+ ['two', '2'],
+ ['three', '3'],
+ ['four(\W|$)', '4\1'], # The weird regex is so that it matches four but not fourty
+ ['five', '5'],
+ ['six(\W|$)', '6\1'],
+ ['seven(\W|$)', '7\1'],
+ ['eight(\W|$)', '8\1'],
+ ['nine(\W|$)', '9\1'],
+ ['ten', '10'],
+ ['\ba[\b^$]', '1'] # doesn't make sense for an 'a' at the end to be a 1
+ ],
+ :ordinals => [
+ ['first', '1'],
+ ['third', '3'],
+ ['fourth', '4'],
+ ['fifth', '5'],
+ ['sixth', '6'],
+ ['seventh', '7'],
+ ['eighth', '8'],
+ ['ninth', '9'],
+ ['tenth', '10']
+ ],
+ :ten_prefixes => [
+ ['twenty', 20],
+ ['thirty', 30],
+ ['forty', 40],
+ ['fourty', 40], # Common mis-spelling
+ ['fifty', 50],
+ ['sixty', 60],
+ ['seventy', 70],
+ ['eighty', 80],
+ ['ninety', 90]
+ ],
+ :big_prefixes => [
+ ['hundred', 100],
+ ['thousand', 1000],
+ ['million', 1_000_000],
+ ['billion', 1_000_000_000],
+ ['trillion', 1_000_000_000_000],
+ ],
+ },
+
+ :repeater => {
+ :season_names => {
+ /^springs?$/ => :spring,
+ /^summers?$/ => :summer,
+ /^(autumn)|(fall)s?$/ => :autumn,
+ /^winters?$/ => :winter
+ },
+ :month_names => {
+ /^jan[:\.]?(uary)?$/ => :january,
+ /^feb[:\.]?(ruary)?$/ => :february,
+ /^mar[:\.]?(ch)?$/ => :march,
+ /^apr[:\.]?(il)?$/ => :april,
+ /^may$/ => :may,
+ /^jun[:\.]?e?$/ => :june,
+ /^jul[:\.]?y?$/ => :july,
+ /^aug[:\.]?(ust)?$/ => :august,
+ /^sep[:\.]?(t[:\.]?|tember)?$/ => :september,
+ /^oct[:\.]?(ober)?$/ => :october,
+ /^nov[:\.]?(ember)?$/ => :november,
+ /^dec[:\.]?(ember)?$/ => :december
+ },
+ :day_names => {
+ /^m[ou]n(day)?$/ => :monday,
+ /^t(ue|eu|oo|u|)s?(day)?$/ => :tuesday,
+ /^we(d|dnes|nds|nns)(day)?$/ => :wednesday,
+ /^th(u|ur|urs|ers)(day)?$/ => :thursday,
+ /^fr[iy](day)?$/ => :friday,
+ /^sat(t?[ue]rday)?$/ => :saturday,
+ /^su[nm](day)?$/ => :sunday
+ },
+ :day_portions => {
+ /^ams?$/ => :am,
+ /^pms?$/ => :pm,
+ /^mornings?$/ => :morning,
+ /^afternoons?$/ => :afternoon,
+ /^evenings?$/ => :evening,
+ /^(night|nite)s?$/ => :night
+ },
+ :units => {
+ /^years?$/ => :year,
+ /^seasons?$/ => :season,
+ /^months?$/ => :month,
+ /^fortnights?$/ => :fortnight,
+ /^weeks?$/ => :week,
+ /^weekends?$/ => :weekend,
+ /^(week|business)days?$/ => :weekday,
+ /^days?$/ => :day,
+ /^hrs?$/ => :hour,
+ /^hours?$/ => :hour,
+ /^mins?$/ => :minute,
+ /^minutes?$/ => :minute,
+ /^secs?$/ => :second,
+ /^seconds?$/ => :second
+ }
+ },
+
+ :pre_normalize => {
+ :preprocess => proc {|str| str},
+ :pre_numerize => [
+ [/\b([ap])\.m\.?/, '\1m'],
+ [/\./, ':'],
+ [/['"]/, ''],
+ [/,/, ' '],
+ [/^second /, '2nd '],
+ [/\bsecond (of|day|month|hour|minute|second)\b/, '2nd \1']
+ ],
+ :pos_numerize => [
+ [/\-(\d{2}:?\d{2})\b/, 'tzminus\1'],
+ [/([\/\-\,\@])/, ' \1 '],
+ [/(?:^|\s)0(\d+:\d+\s*pm?\b)/, ' \1'],
+ [/\btoday\b/, 'this day'],
+ [/\btomm?orr?ow\b/, 'next day'],
+ [/\byesterday\b/, 'last day'],
+ [/\bnoon\b/, '12:00pm'],
+ [/\bmidnight\b/, '24:00'],
+ [/\bnow\b/, 'this second'],
+ ['quarter', '15'],
+ ['half', '30'],
+ [/(\d{1,2}) (to|till|prior to|before)\b/, '\1 minutes past'],
+ [/(\d{1,2}) (after|past)\b/, '\1 minutes future'],
+ [/\b(?:ago|before(?: now)?)\b/, 'past'],
+ [/\bthis (?:last|past)\b/, 'last'],
+ [/\b(?:in|during) the (morning)\b/, '\1'],
+ [/\b(?:in the|during the|at) (afternoon|evening|night)\b/, '\1'],
+ [/\btonight\b/, 'this night'],
+ [/\b\d+:?\d*[ap]\b/,'\0m'],
+ [/\b(\d{2})(\d{2})(am|pm)\b/, '\1:\2\3'],
+ [/(\d)([ap]m|oclock)\b/, '\1 \2'],
+ [/\b(hence|after|from)\b/, 'future'],
+ [/^\s?an? /i, '1 '],
+ [/\b(\d{4}):(\d{2}):(\d{2})\b/, '\1 / \2 / \3'], # DTOriginal
+ [/\b0(\d+):(\d{2}):(\d{2}) ([ap]m)\b/, '\1:\2:\3 \4']
+ ]
+ },
+
+ :grabber => {
+ /last/ => :last,
+ /this/ => :this,
+ /next/ => :next
+ },
+
+ :token => {
+ :comma => /^,$/,
+ :at => /^(at|@)$/,
+ :in => /^in$/,
+ :on => /^on$/,
+ :and => /^and$/
+ }
+ }
+ end
+end
Oops, something went wrong.

0 comments on commit 024943d

Please sign in to comment.