i18n-inflector-2.6.7/ 0000755 0000041 0000041 00000000000 13321144047 014317 5 ustar www-data www-data i18n-inflector-2.6.7/Gemfile.lock 0000644 0000041 0000041 00000000775 13321144047 016552 0 ustar www-data www-data GEM
remote: https://rubygems.org/
specs:
hoe (2.16.1)
rake (~> 0.8)
hoe-bundler (1.2.0)
hoe (>= 2.2.0)
hoe-yard (0.1.2)
yard (>= 0.2.3.1)
i18n (0.6.4)
json (1.8.0)
rake (0.9.6)
rdoc (4.0.1)
json (~> 1.4)
test_declarative (0.0.5)
yard (0.8.6.1)
PLATFORMS
ruby
DEPENDENCIES
bundler (>= 1.0.15)
hoe (~> 2.16)
hoe-bundler (>= 1.2.0)
hoe-yard (>= 0.1.2)
i18n (>= 0.4.1)
rdoc (>= 3.8.0)
test_declarative (>= 0.0.5)
yard (>= 0.8.6)
i18n-inflector-2.6.7/docs/ 0000755 0000041 0000041 00000000000 13321144047 015247 5 ustar www-data www-data i18n-inflector-2.6.7/docs/COPYING 0000644 0000041 0000041 00000004674 13321144047 016315 0 ustar www-data www-data i18n-inflector is copyrighted free software owned by Paweł Wilk (pw@gnu.org). The Owner of this software permits you to redistribute and/or modify the software under either the terms of the LGPL version 3 (see the file {file:docs/LGPL LGPL-LICENSE}), or the conditions below ("Ruby License").
== 1.
You may make and give away verbatim copies of the source form of this software without restriction, provided that you retain ALL of the
original copyright notices and associated disclaimers.
== 2.
You may modify your copy of the software in any way, provided that you do at least ONE of the following:
a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said
modifications to Usenet or an equivalent medium, or by allowing
the author to include your modifications in the software.
b) use the modified software only within your corporation or
organization.
c) give non-standard binaries non-standard names, with
instructions on where to get the original software distribution.
d) make other distribution arrangements with the Owner.
== 3.
You may distribute the software in object code or binary form, provided that you do at least ONE of the following:
a) distribute the binaries and library files of the software,
together with instructions (in a manual page or equivalent)
on where to get the original distribution.
b) accompany the distribution with the machine-readable source of
the software.
c) give non-standard binaries non-standard names, with
instructions on where to get the original software distribution.
d) make other distribution arrangements with the Owner.
== 4.
You may modify and include parts of the software into any other software (possibly commercial), provided you comply with the terms in
Sections 1, 2, and 3 above. But some files in the distribution are not written by the Owner, so they may be made available to you
under different terms.
For the list of those files and their copying conditions, see the
file LEGAL.
== 5.
The scripts and library files supplied as input to or produced as output from the software do not automatically fall under the
copyright of the software, but belong to whoever generated them, and may be sold commercially, and may be aggregated with this software.
== 6.
THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
i18n-inflector-2.6.7/docs/LGPL 0000644 0000041 0000041 00000016335 13321144047 015740 0 ustar www-data www-data
= GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. < http://fsf.org/ >
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
=== 0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
=== 1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
=== 2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
=== 3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
=== 4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
=== 5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
=== 6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
i18n-inflector-2.6.7/docs/EXAMPLES 0000644 0000041 0000041 00000023617 13321144047 016421 0 ustar www-data www-data
== Configuring inflections
This data will be used in any further example:
=== YAML
en:
i18n:
inflections:
@person:
i: "i"
u: "you"
he: "he"
she: "she"
it: "it"
you: @u
gender:
m: "male"
f: "female"
n: "neuter"
default: n
welcome: "Dear @{f:Lady|m:Sir|n:You|All}!"
sayit: "@person{i:I|u:You|he:He|she:She|it:It}{ }{i:am|u:are|he,she,it:is}"
tobe: "%{person} @person{i:am|u:are|he,she,it:is}"
=== Code
I18n.backend.store_translations(:en, :i18n => { :inflections => {
:gender => {
:m => 'male',
:f => 'female',
:n => 'neuter',
:default => :n
},
:@person => {
:i => 'i',
:u => 'you',
:he => 'he',
:she => 'she',
:it => 'it',
:you => :@u
}
}})
I18n.backend.store_translations(:en, 'welcome' => 'Dear @{f:Lady|m:Sir|n:You|All}!')
I18n.backend.store_translations(:en, 'sayit' => '@person{i:I|u:You|he:He|she:She|it:It}{ }{i:am|u:are|he,she,it:is}')
I18n.backend.store_translations(:en, 'tobe' => '%{person} @person{i:am|u:are|he,she,it:is}')
I18n.locale = :en
== Simple interpolation
When no option, it falls back to default token (n):
I18n.translate('welcome')
#=> "Dear You!"
When :m, it interpolates the m token's value:
I18n.translate('welcome', :gender => :m)
#=> "Dear Sir!"
When unknown, it falls back to default token (n):
I18n.translate('welcome', :gender => :unknown)
#=> "Dear You!"
When +nil+, it falls back to default token (n):
I18n.translate('welcome', :gender => nil)
#=> "Dear You!"
=== inflector_unknown_defaults
When :inflector_unknown_defaults is false, it falls back to free text:
I18n.translate('welcome', :gender => :unknown, :inflector_unknown_defaults => false)
#=> "Dear All!"
It also falls back when an inflection option is nil or empty:
I18n.translate('welcome', :gender => nil, :inflector_unknown_defaults => false)
#=> "Dear All!"
== Named pattern
Regular inflection option will be used if there is no strict inflection option:
I18n.translate('sayit', :person => :i)
#=> "I am"
Strict inflection option has precedence:
I18n.translate('sayit', :person => :i, :@person => :u)
#=> "You are"
Strict inflection option has precedence even if the option's value is messy:
I18n.translate('sayit', :person => :i, :@person => :unknown)
#=> " "
=== Using with interpolation argument
First part is interpolated using standard interpolation variable while
second part of the sentence comes from interpolation of inflection pattern.
The same option is feeding both engines.
I18n.translate('tobe', :person => :i)
#=> "i am"
Note funny thing. The interpolation variable +test+ takes value (+i+) from
+:person+ while option +:@person+ takes precedence when it comes to inflections.
Keep that in mind when combining regular interpolation variables with named patterns
while using the same variable for controlling both. Choose non-strict notation
for an option then.
I18n.translate('tobe', :person => :i, :@person => :u)
#=> "i are"
No free text in 'tobe' so the empty string is interpolated when strict kind is unknown:
I18n.translate('tobe', :person => :i, :@person => :unknown)
#=> "i "
== API
=== Getting kinds
Getting all known regular kinds:
I18n.inflector.kinds
#=> [:gender]
Getting all known strict kinds:
I18n.inflector.strict.kinds
#=> [:person]
Getting all known kinds for language 'pl':
I18n.inflector.kinds(:pl)
#=> []
=== Listing all known options
I18n.inflector.options.known
#=> [:inflector_cache_aware, :inflector_raises, :inflector_aliased_patterns,
# :inflector_unknown_defaults, :inflector_excluded_defaults]
== Real-life example for Polish language
Polish is highly inflected language. Additionally, position of a word in
a sentence is mutually coupled with meaning. That makes it extreemly
hard to create finite-state machine that would handle Polish grammar.
However, flection means that the same cores are combined with suffixes
and prefixes depending on many different kinds: gender, tense, form,
animation, declination and more. That makes Polish (and other Slavic
languages) alphabetically redundant. By interpolating common cores,
prefixes and suffixes of words we're able make our patterns compact.
=== YAML
pl:
are_you_sure: "@{m,f:Jesteś pew}{m:ien|f:na}{n:Na pewno}?"
i18n:
inflections:
gender:
f: "rodzaj żeński"
m: "rodzaj męski"
n: "forma bezosobowa"
masculine: @m
facet: @m
chłopak: @m
feminine: @f
pani: @f
kobieta: @f
k: @f
dziewczyna: @f
impersonal: @n
default: n
=== Code
# Using shorter form than listed as YAML
I18n.backend.store_translations(:pl, :i18n => { :inflections => { :gender =>
{ :f => 'f', :m=>'m', :n=>'n', :kobieta=>:@f, :facet => :@m, :default=>:n }}})
# Making use of commas makes it easy to implement DRY
# and re-use some parts of the words that are the same in two or more phrases
I18n.backend.store_translations(:pl, :are_you_sure => "@{m,f:Jesteś pew}@{m:ien|f:na}@{n:Na pewno}?")
I18n.locale = :pl
I18n.translate('are_you_sure', :gender => :kobieta)
#=> "Jesteś pewna?"
I18n.translate('are_you_sure', :gender => :facet)
#=> "Jesteś pewien?"
I18n.translate('are_you_sure')
#=> "Na pewno?"
# It would look like that without commas:
I18n.backend.store_translations(:pl, :are_you_sure => "@{m:Jesteś pewien|f:Jesteś pewna|n:Na pewno}?")
# That would also work but it's less readable.
# PS: Have you ever configured Sendmail? ;-)
I18n.backend.store_translations(:pl, :are_you_sure => "@{n:Na|m,f:Jesteś}{ pew}{m:ie}{n}{f:a|n:o}?")
=== Complex pattern usage
# Store needed translations
I18n.backend.store_translations(:pl,
:i18n => { :inflections => {
:@gender =>
{ :f => 'f', :m => 'm', :n => 'n',
:kobieta => :@f, :facet => :@m, :default => :n },
:@tense =>
{ :t => 'teraz', :w => 'przeszły', :j => 'przyszły',
:teraz => :@t, :wczoraj => :@w, :jutro => :@j,
:default => :t }
}})
I18n.backend.store_translations(:pl,
:msg_receive => "@gender+tense{n+w:Otrzymano|Dosta}{*+t:jesz|*+j:niesz|f+w:łaś|m+w:łeś} wiadomość")
I18n.locale = :pl
p I18n.translate('msg_receive', :gender => :kobieta)
#=> "Dostajesz wiadomość"
p I18n.translate('msg_receive', :gender => :facet)
#=> "Dostajesz wiadomość"
p I18n.translate('msg_receive')
#=> "Dostajesz wiadomość"
p I18n.translate('msg_receive', :gender => :kobieta, :tense => :wczoraj)
#=> "Dostałaś wiadomość"
p I18n.translate('msg_receive', :gender => :facet, :tense => :wczoraj)
#=> "Dostałeś wiadomość"
p I18n.translate('msg_receive', :tense => :jutro)
#=> "Dostaniesz wiadomość"
p I18n.translate('msg_receive', :tense => :wczoraj)
#=> "Otrzymano wiadomość"
==== YAML for the example above
The example above may use this YAML content instead of +store_translations+:
pl:
msg_receive: "@gender+tense{n+w:Otrzymano|Dosta}{*+t:jesz|*+j:niesz|f+w:łaś|m+w:łeś} wiadomość"
i18n:
inflections:
@gender:
m: 'male'
f: 'female'
n: 'neuter'
kobieta: @f
facet: @m
default: n
@tense:
t: 'teraźniejszy'
w: 'przeszły'
j: 'przyszły'
teraz: @t
wczoraj: @w
jutro: @j
default: @t
===== Alternative for +msg_receive+ key
The +msg_receive+ might also be expressed using two infleciton keys:
pl:
@msg_receive_1:
@kind: gender+tense
@free: 'Dosta'
n+w: 'Otrzymano'
@msg_receive_2:
@kind: gender+tense
@suffix: " wiadomość"
m,f,n+t: "jesz"
m,f,n+j: "niesz"
f+w: "łaś"
m+w: "łeś"
But then you have to change the translation call too, e.g.:
p I18n.translate(['@msg_receive_1','@msg_receive_2'], :gender => :kobieta).join
#=> "Dostajesz wiadomość"
The split is necessary because we have two patterns here and no way to express them
as one inflection key.
== To be or not to be
Here is the example pattern that inflects English to be by tense,
person and grammatical number:
en:
i18n:
inflections:
@person:
1: first
2: second
3: third
i: :@1
you: :@2
He: :@3
She: :@3
it: :@3
@tense:
past: past
present: present
now: @present
default: present
@num:
s: singular
p: plural
default: s
to_be: >
@num+person{s+1:I|*+2:You|s+3:%{person}|p+3:They|p+1:We}
@num+person+tense{s+1+present:am|s+2+present:are|s+3+present:is|
p+*+present:are|s+1,3+past:was|p+*+past:were|s+2+past:were}
And the code that prints all possible combinations:
[:i, :you, :He, :She, :It].each do |person|
puts I18n.translate(:to_be, :num => :s, :person => person, :tense => :now) + "\t| " +
I18n.translate(:to_be, :num => :s, :person => person, :tense => :past)
end
puts
(1..3).each do |person|
puts I18n.translate(:to_be, :num => :p, :person => person, :tense => :now) + " | " +
I18n.translate(:to_be, :num => :p, :person => person, :tense => :past)
end
to be continued…
i18n-inflector-2.6.7/docs/rdoc.css 0000600 0000041 0000041 00000000614 13321144047 016701 0 ustar www-data www-data @import "rdoc_base.css";
#documentation > ul:first-of-type {
padding-bottom: 2em;
padding-top: 1.5em;
background-position: 20em 0%;
background-repeat: no-repeat;
}
#documentation .method-description > p:first-of-type + p {
margin-top: 0.5em;
}
#documentation .method-description > ul {
margin-left: 1.2em;
}
#documentation .method-description > p + ul {
margin-left: 1.8em;
}
i18n-inflector-2.6.7/docs/TODO 0000644 0000041 0000041 00000001220 13321144047 015732 0 ustar www-data www-data == Near future
* allow nested vaules: pattern values that refer to other translation keys (needs loop detection) (doc name: nesting patterns)
* add unfold method that whill generate array or hash with all possible combinations of a given translation
(lazy?)
e.g: unfold('welcome') # :only_used => false|true, :recursive => false|true
=> :levels => [:gender, :tense, :time]
[:welcome][:m][:p] = 'hello sir'
== Distant future
* split interpolate_core and make it more reusable by raw data (e.g. pattern content)
* allow different descriptions for aliases pointing to the same token, e.g.: now: [@present, "description"]
i18n-inflector-2.6.7/docs/LEGAL 0000644 0000041 0000041 00000000570 13321144047 016020 0 ustar www-data www-data LEGAL NOTICE INFORMATION
------------------------
i18n-inflector is Copyright (C) 2011,2012 by Paweł Wilk.
i18n-inflector is copyrighted software owned by Paweł Wilk
(pw@gnu.org). You may redistribute and/or modify this
software as long as you comply with either the terms of the LGPL
(see the file {file:docs/LGPL}),
or Ruby's license (see the file {file:docs/COPYING}).
i18n-inflector-2.6.7/docs/HISTORY 0000644 0000041 0000041 00000015421 13321144047 016336 0 ustar www-data www-data === 2.6.7 / 2013-06-18
* major compatibility fixes
* Removed deprecation warnings for Ruby 2.0
* minor enhancements
* Updated gem dependencies
=== 2.6.6 / 2012-03-14
* major enhancements
* Added support for integers as token names
* Added nice example of "to be" inflection in English
* minor enhancements
* Documentation updated
* Added instance method empty? to LazyEnumerator
=== 2.6.5 / 2012-03-10
* minor enhancements
* Back to Psych YAML parser while creating gem
=== 2.6.4 / 2012-03-10
* minor enhancements
* Changed documentation examples for calling rake
* Tested against Ruby 1.9.3-p0
* Updated dependencies
* Updated copyright notices
* Started codenaming each version (including minor version numbers)
=== 2.6.2 / 2011-08-07
* minor bugfixes
* Applied a workaround against a buggy parser in Rubygems
=== 2.6.1 / 2011-07-10
* major enhancements
* Handling of methods and Proc objects used to obtain inflection options improved by caching
* Added caching for methods reporting locales that support inflection
* Lazy operations optimized
* minor enhancements
* Fixed documentation links
* Dependencies updated
=== 2.6.0 / 2011-03-08
* minor enhancements
* Strings concatenation optimized
* API methods simplified
* Added lazy iteration methods to I18n::Inflector::InflectionData and I18n::Inflector::InflectionData_Strict
* Added lazy iteration methods to I18n::Inflector::API and I18n::Inflector::API_Strict
=== 2.5.1 / 2011-02-25
* minor enhancements
* Added the ability to use symbols as descriptions (values) in a configuration
=== 2.5.0 / 2011-02-24
* major enhancements
* Interpolation wrapper refactored; works with many types of results
* Added :inflector_interpolate_symbols switch
* minor enhancements
* Added TOKENS_RESTR, MULTI_RESTR and PATTERN_RESTR configuration constants
* Dependencies updated
* major bugfixes
* Fixed interpolation of Arrays
* minor bugfixes
* Fixed pattern filtering when locale is invalid or not inflected
=== 2.4.0 / 2011-02-23
* major enhancements
* Added nested translations (collections) support
* Added :inflector_traverses switch
=== 2.3.1 / 2011-02-14
* major enhancements
* Added wildcard tokens support
* Proc and Method kind of objects might be passed as inflection options
* minor enhancements
* Added I18n::Inflector::Config::Markers::STRICT_KIND (character used when passing strict kinds)
* Important documentation moved to the USAGE file
* minor bugfixes
* Fixed parsing of named patterns when :inflector_excluded_defaults is used
* Fixed links in documentation
=== 2.2.0 / 2011-02-09
* major enhancements
* Added loud tokens support
* Added complex patterns support
* Added key-based inflection support
* Added :cache_aware switch
* Improved validation of token and kind identifiers
* minor enhancements
* Refactored error reporting code
* Refactored options gathering code
* Removed magic symbols and strings
* Removed intermediate array from LazyHashEnumerator#to_h
* Added multiple patterns support (syntactic sugar)
* Added I18n::Inflector::Config module
* Added I18n::Inflector::LazyArrayEnumerator class
* Added I18n::Inflector::HSet class for keeping collections of data
* Added error classes: I18n::InvalidInflectionOption and I18n::InvalidInflectionKind
* Interpolation method moved to I18n::Inflector::Interpolate module
* All inflection related exceptions now have the attribute "key" containing key name
* major bugfixes
* Fixed handling of missing inflection option when :inflector_raises is set
* minor bugfixes
* Fixed interpolation when :excluded_defaults is on and a kind is strict
* Fixed interpolation when pattern is escaped and locale is not inflected
* Enabled filtering of reserved names in options
* Enabled filtering of inflection options for options that go to original translate method
* Updated documentation in a section describing options
* Fixed some examples
=== 2.1.0 / 2011-01-27
* major enhancements
* Added named patterns support (strict kinds)
* API improved: major class is I18n::Inflector::API
* Added class I18n::Inflector::API_Strict for accessing strict inflections
* Added lazy enumerators for internal hashes, which saves some memory
* Added strict kinds detection (@-style kind names) to most of the methods from main API class
* Added new error classes: InflectionOptionNotFound and InflectionOptionIncorrect
* Added class for handling inflection data for strict kinds: I18n::Inflector::InflectionData_Strict
* Inflections for regular and strict kinds are handled by separate data structures and objects
* Documentation updated
* minor bugfixes
* Error reporting fixed in some places
* Strict kinds interpolation improved
* Removed some slow blocks
* Loading inflection tokens cleaned up
=== 2.0.1 / 2011-01-15
* minor enhancements
* Documentation updated
* minor bugfixes
* Fixed duplicated dependency generation in Hoe
=== 2.0.0 / 2011-01-14
* major enhancements
* API changed
* Added a class for keeping internal inflection data: I18n::Inflector::InflectionData
* Added a class for keeping options: I18n::Inflector::InflectionOptions
* Added a class for controlling the inflection: I18n::Inflector::Core
* Added a module for utilities: I18n::Inflector::Util
* Added token groups support
* Added inversed matching of tokens in inflection patterns
* Added support for aliases in inflection patterns
* Most of the methods from I18n::Backend::Inflector moved to Core submodule
* Most methods rewritten
=== 1.0.10 / 2011-01-10
* major bugfixes
* Removed cause of infinite loops while initializing translations
* Disabled lookup from being used before translations are initialized
* Fixed initialization routine (dangerous typo when setting booleans)
* minor enhancements
* Switched to lazy loading of inflection data for certain locales
=== 1.0.8 / 2011-01-08
* major enhancements
* Enabled escaping of patterns using @@{pattern} or \@{pattern}
=== 1.0.7 / 2011-01-07
* major bugfixes
* Fixed interpolation when a translated string begins with a pattern
=== 1.0.6 / 2010-12-30
* minor enhancements
* Added API method inflection_kind(token)
* Added API method inflection_true_token(token)
* Added API method inflected_locale(locale)
=== 1.0.5 / 2010-12-29
* major enhancements
* Compatible with i18n >= 0.4.1
=== 1.0.4 / 2010-12-27
* minor enhancements
* Documentation updated
=== 1.0.3 / 2010-12-25
* major enhancements
* YARD documentation updated with metatags
* minor enhancements
* Some changes in accessors for interpolation switches
=== 1.0.2 / 2010-12-22
* minor enhancements
* Switched to YARD documentation
* Tests simplified
* Depandencies simplified
=== 1.0.0 / 2010-12-22
* 1 major enhancement
* Birthday!
i18n-inflector-2.6.7/docs/USAGE 0000644 0000041 0000041 00000104511 13321144047 016040 0 ustar www-data www-data = Usage of the I18n Inflector
The {I18n::Inflector I18n Inflector} contains inflection classes
and modules for enabling the inflection support in I18n translations.
It is also used by the module called {I18n::Backend::Inflector}
that overwrites the translate method from the Simple backend
so it will interpolate additional inflection data present
in translations. That data may appear in *patterns*
enclosed within @{ and } symbols. Each pattern
consist of *tokens* and respective *values*. One of the value will
be used depending on additional data passed to the translate method.
That additional data is called inflection options.
== Usage
require 'i18-inflector'
i18n.translate('welcome', :gender => :f)
# => Dear Madam
i18n.inflector.kinds
# => [:gender]
i18n.inflector.true_tokens.keys
# => [:f, :m, :n]
See the {file:docs/EXAMPLES} for more information about real-life
usage of Inflector.
== Inflection pattern
An example inflection pattern stored under a translation key looks like:
welcome: "Dear @{f:Madam|m:Sir|n:You|All}"
The +f+, +m+ and +n+ are inflection *tokens* and +Madam+, +Sir+, +You+ and
+All+ are *values*. Only one value is going to replace the whole
pattern. To select which one an additional option is used. That option
must be passed to the translate method.
There are also so called named patterns that will be explained
later.
== Configuration
To recognize tokens present in patterns keys grouped
in the scope called +inflections+ for the given locale are used.
For instance (YAML format):
en:
i18n:
inflections:
gender:
f: "female"
m: "male"
n: "neuter"
man: @m
woman: @f
default: n
Elements in the example above are:
* +en+: language
* +i18n+: configuration scope
* +inflections+: inflections configuration scope
* +gender+: kind scope
* +f+, +m+, +n+: inflection tokens
* "male", "female", "neuter": tokens' descriptions
* +woman+, +man+: inflection aliases
* @f, @m: pointers to real tokens
* +default+: default token for a kind +gender+
=== Note about YAML parsing
The example above is not compatible with Psych parser, which is used
by Rails 3. There are two ways to solve that problem.
First is to make a change in a YAML file and replace any value that has
special meaning with a symbol:
en:
i18n:
inflections:
gender:
f: "female"
m: "male"
n: "neuter"
female: :@f
male: :@m
default: :n
Second way is to use other parser by adding to +config/boot.rb+:
require 'yaml'
YAML::ENGINE.yamler = 'syck'
Note that all the examples in this documentation use the less strict format.
If you will encounter any parsing problems in your application then change
all problematic inflection values in YAML files into symbols.
=== Kind
Note the fourth scope selector in the example above (+gender+). It's called
the *kind* and contains *tokens*. We have the kind
+gender+ to which the inflection tokens +f+, +m+ and +n+ are
assigned.
You cannot assign the same token to more than one kind.
Trying to do that will raise {I18n::DuplicatedInflectionToken} exception.
This is required in order to keep patterns simple and tokens interpolation
fast.
Kind is also used to instruct {I18n::Backend::Inflector#translate} method which
token it should pick. This is done through options and
will be explained later.
There is also a class of kind called strict kind used by
named patterns; that will be explained later.
=== Tokens
The token is an element of a pattern. Any pattern may have many tokens
of the same kind separated by vertical bars. Optionally tokens might
be groupped using commas (these are token groups; that will be explained
later). Each token name (or a group of tokens) used in a pattern should
end with colon sign. After this colon a value should appear (or an empty
string).
Tokens also appear in a configuration data. They are assigned to kinds.
Token names must be unique across all kinds, since it would be impossible
for interpolation routine to guess a kind of a token present in a pattern.
There is however a class of kinds called strict kinds, for which tokens
must be unique only within a kind. The named patterns that are using
strict kinds will be explained later.
=== Aliases
Aliases are special tokens that point to other tokens. By default they
cannot appear in inflection patterns but they are fully recognized
in options that are be passed to the translation method.
Aliases might be helpful in multilingual applications that are using
a fixed set of values passed through options to describe some properties
of messages, e.g. +masculine+ and +feminine+ for a grammatical gender.
Translators will then use their own tokens (like +f+ and +m+ for English)
to produce pretty and intuitive patterns.
For example: if some application uses database with gender assigned
to a user which may be +male+, +female+ or +none+, then a translator
may find it useful to map impersonal token (none)
to the +neuter+ token, since in translations for his language the
neuter gender is in use.
Here is the example of such situation:
en:
i18n:
inflections:
gender:
male: "male"
female: "female"
none: "impersonal form"
default: none
pl:
i18n:
inflections:
gender:
k: "female"
m: "male"
n: "neuter"
male: @k
female: @m
none: @n
default: none
In the case above Polish translator decided to use neuter
instead of impersonal form when +none+ token will be passed
through the option +:gender+ to the translate method. He
also decided that he will use +k+, +m+ or +n+ in patterns,
because the names are short and correspond to gender names in
Polish language: +k+ for 'kobieta' (woman), +m+ for 'mężczyzna' (man),
+n+ for 'nijaki' (neuter).
Aliases may point to other aliases. While loading inflections they
will be internally shortened and they will always point to real tokens,
not other aliases.
=== Default token
There is a special token called the +default+, which points
to a token that should be used if the interpolation routine cannot deduce
which one it should use because a proper option was not given.
Default tokens may point to aliases and may use aliases' syntax, e.g.:
default: @man
=== Descriptions
The values of keys in the example (+female+, +male+ and +neuter+)
are *descriptions* which usually are not used by the interpolation routine
but might be helpful (e.g. in UI). For obvious reasons you cannot
describe aliases.
== Interpolation
The value of each token present in a pattern is to be picked by the interpolation
routine and will replace the whole pattern, when a token name from that
pattern matches the given value of an option passed to the {I18n.translate} method.
=== Inflection option
The mentioned option is called the inflection option. Its name should be
the same as a *kind* of tokens used within a pattern. The first token in a pattern
determines the kind of all tokens used in that pattern. You can pass
many inflection options, each one designated for transporting a token of a
different kind.
==== Examples
*YAML:*
Let's assume that the translation data in YAML format listed
below is used in any later example, unless other inflections
are given.
en:
i18n:
inflections:
gender:
m: "male"
f: "female"
n: "neuter"
default: n
welcome: "Dear @{f:Madam|m:Sir|n:You|All}"
*Code:*
I18n.translate('welcome', :gender => :m)
# => "Dear Sir"
I18n.translate('welcome', :gender => :unknown)
# => "Dear All"
I18n.translate('welcome')
# => "Dear You"
In the second example the fallback value +All+ was interpolated
because the routine had been unable to find the token called +:unknown+.
That differs from the latest example, in which there was no option given,
so the default token for a kind had been applied (in this case +n+).
==== Inflection options as Methods or Procs
The inflection option may contain an object that is a kind of Method or
a Proc. The token will be obtained by calling the given method or a block when
interpolation routine will need it.
The passed method or a block should return an object that is a kind of
Symbol. It will be used as an inflection token.
Optionally the inflection method may make use of a block that is passed
to it. Currently two parameters can be obtained using the keyword +yield+.
Fist is the currenty parsed kind (including +@+ character in case of
a strict kind) and second is the locale; both are the kind of Symbol. Example:
def get_gender
kind, locale = yield # optional
:n # return token n
end
translate('welcome', :gender => method(:get_gender))
In case of Proc, the arguments are passed in a more comprehensive way,
as parameters passed to a block. Such a block must handle exactly
two arguments:
p = lambda{ |kind, locale| :m }
translate('welcome', :gender => p)
Note that if there will be any error that causes exception to be
raised by such a method or a block then it will be raised regardless
of +:inflector_raises+ option.
=== Local fallbacks (free text)
The fallback value will be used when none of the tokens contained
within a pattern can be interpolated.
Be aware that enabling extended error reporting makes it unable
to use fallback values in most cases. Local fallbacks will then be
applied only when the given option contains a proper value for some
kind but it's just not present in a pattern, for example:
*YAML:*
en:
i18n:
inflections:
gender:
n: 'neuter'
o: 'other'
welcome: "Dear @{n:You|All}"
*Code:*
I18n.translate('welcome', :gender => :o, :inflector_raises => true)
# => "Dear All"
# since the token :o was configured but not used in the pattern
=== Bad and empty tokens in options
If an option containing token is not present at all then the interpolation
routine will try the default token for a processed kind, if the default
token is present in a pattern. The same thing will happend if the option
is present but its value is malformed, unknown, empty or +nil+.
If the default token is not present in a pattern or is not defined in
a configuration data then the processing of a pattern will result
in an empty string or in a local fallback value if there is
a free text placed in a pattern.
You can change this default behavior and force inflector
not to use a default token when a value of an option for
a kind is malformed, unknown, empty or +nil+ but only when
it's not present. To do that you should set option +:inflector_unknown_defaults+
to +false+ and pass it to the translate method. Other way is to set this
switch globally using the {I18n::Inflector::InflectionOptions#unknown_defaults}.
=== Unmatched tokens in options
It might happend that there will be a default token present in a pattern
but the given inflection option will cause some other token to be picked up,
which however won't be present in this pattern (although it will be
correct and assigned to the currently processed kind). In such
case the given free text or an empty string will be generated.
You may change that behavior by passing +:inflector_excluded_defaults+
option set to +true+ or by setting the global option called
{I18n::Inflector::InflectionOptions#excluded_defaults}. If this
option is set then any unmatched (excluded but correct) token
given in an inflection option will cause the default token's value
to be picked up (of course if a default token will be present
in a pattern).
=== Mixing inflection and standard interpolation patterns
The Inflector allows you to include standard %{}
patterns inside of inflection patterns. The value of a standard
interpolation variable will be evaluated and interpolated *before*
processing an inflection pattern. For example:
*YAML:*
Note: Uses inflection configuration given in the first example.
en:
hi: "Dear @{f:Lady|m:%{test}}!"
*Code:*
I18n.t('hi', :gender => :m, :locale => :xx, :test => "Dude")
# => Dear Dude!
=== Token groups
It is possible to assign some value to more than one token in a patterns.
You can create group of tokens by separating them using commas.
The comma has the meaning of logical OR.
*YAML:*
Note: Uses inflection configuration given in the first example.
en:
welcome: "Hello @{m,f:Ladies and Gentlemen|n:You}!"
*Code:*
I18n.t('welcome', :gender => :f)
# => Hello Ladies and Gentlemen!
=== Inversed matching of tokens
You can place exclamation mark before a token that should be
matched negatively. Its value will be used for a pattern
if the given inflection option contains other token.
You can use inversed matching of tokens in token groups but
note that putting more than one inversed token to a group
will cause the expression to mach every time.
*YAML:*
Note: Uses inflection configuration given in the first example.
en:
welcome: "Hello @{!m:Ladies|n:You}!"
*Code:*
I18n.t('welcome', :gender => :n)
# => Hello Ladies!
I18n.t('welcome', :gender => :f)
# => Hello Ladies!
I18n.t('welcome', :gender => :m)
# => Hello !
=== Wildcard tokens
You may use the wildcard character, a star (+*+), in place of token
group to create a virtual token that matches any token of a parsed kind.
For example:
*YAML:*
Note: Uses inflection configuration given in the first example.
en:
welcome: "Hello @{n:you|*:ladies and gentlemen}!"
*Code:*
I18n.t('welcome', :gender => :n)
# => Hello you!
I18n.t('welcome', :gender => :f)
# => Hello ladies and gentlemen!
Note that for simple patterns you can use free text instead, which works
almost the same way with one significant difference: free text will be
evaluated as the last expression, regardless of its placement.
On the contrary a wildcard token will be evaluated as any other
token group and may not be used if any previously tested token
will match (like +n+ in the example above).
While a wildcard token is processed then the interpolation routine
will validate if the required inflection option exists and if it contains
a proper token. Using wildcard token is like using a token group
for any other token group containing all possible true tokens in it.
In case of regular patterns containing just a wildcard token alone
there is no way to easily decide which kind the expression
refers to. To deduce it the first valid inflection option will
be used. In order to work it must contain some valid token
identifier. If the token identifier is invalid and there are more
inflection options then they are tried.
Wildcard tokens are useful in so called complex patterns which
will be explained later.
=== Loud tokens
Sometimes there might be a need to use descriptions of
matching tokens instead of some given values. Use loud tokens
to achieve that. Any matching token in a pattern that has tilde symbol (+~+)
set as its value will be replaced by its description. In case of
undescribed aliases, the description from a target token will be used.
*YAML:*
Note: Uses inflection configuration given in the first example.
en:
welcome: "Hello @{m:~|n:~}!"
*Code:*
I18n.t('welcome', :gender => :n)
# => Hello neuter!
I18n.t('welcome', :gender => :f)
# => Hello female!
To use tilde symbol as the only value of a token you may esape it
by putting a backslash in front of the symbol.
Using loud token with wildcard token will result in a description
of first matching token.
=== Aliases in a pattern
Normally it is possible to use in patterns only true tokens, not aliases.
However, if you feel lucky and you're not affraid of messy patterns
you can use the switch {I18n::Inflector::InflectionOptions#aliased_patterns}
or pass corresponding +:inflector_aliased_patterns+ option to the translate
method.
=== Escaping a pattern
If there is a need to translate something that accidentally matches
an inflection pattern then the escape symbols can be used to
disable the interpolation. These symbols are \\ and +@+
and they should be placed just before a pattern that should
be left untouched. For instance:
*YAML:*
Note: Uses inflection configuration given in the first example.
en:
welcome: "This is the @@{pattern}!"
*Code:*
I18n.t('welcome', :gender => :m, :locale => :xx)
# => This is the @{pattern}!
=== More about applying aliases
It may seem very easy and attractive to use aliases
in environments where inflection option's value comes from a user.
In such cases aliases may be used as database that translates common
words to inflection tokens that have meanings. For example a user may
enter a gender in some text field and it will be used as value of inflection
option. To map different names (e.g. male, boy, sir, female, girl, lady)
to exact inflection tokens the aliases would be used.
Note hovewer, that you can make use of I18n.inflector.true_token
method (see {I18n::Inflector::API#true_token}) that will resolve any alias,
and then use that data to feed an inflection option (e.g. +:gender+).
In such scenario you don't have to rely on resolving aliases
any time translation is performed and you will gain some speed.
== Named patterns
A named pattern is a pattern that contains name of a kind
that tokens from a pattern are assigned to. It looks like:
welcome: "Dear @gender{f:Madam|m:Sir|n:You|All}"
=== Configuring named patterns
To recognize tokens present in named patterns,
inflector uses keys grouped in the scope called +inflections+
for the given locale. For instance (YAML format):
en:
i18n:
inflections:
@gender:
f: "female"
woman: @f
default: f
Elements in the example above are:
* +en+: language
* +i18n+: configuration scope
* +inflections+: inflections configuration scope
* +gender+: strict kind scope
* +f+: inflection token
* "female": token's description
* +woman+: inflection alias
* @f: pointer to real token
* +default+: default token for a strict kind +gender+
=== Strict kinds
In order to handle named patterns properly a new data structure
is used. It is called the strict kind. Strict kinds are defined
in a configuration in a similar way the regular kinds are but
tokens assigned to them may have the same names across a whole
configuration. (Note that tokens of the same strict kind should still
be unique.) That implies a requirement of passing the
identifier of a kind in patterns when referring to such tokens.
Here is the example configuration using strict kinds:
en:
i18n:
inflections:
@gender:
f: "female"
m: "male"
n: "neuter"
man: @m
woman: @f
default: n
@title:
s: "sir"
l: "lady"
u: "you"
m: @s
f: @l
default: u
The only thing that syntactically distinguishes strict kinds
from regular kinds is a presence of the +@+ symbol.
You can mix regular and strict kinds having the same names in
one translation entry, but not in one inflection pattern.
The proper class of kind will be picked up by interpolation
method easily, since the first mentioned class uses
patterns that are not named, and the second uses named patterns.
==== Strict kinds in inflection options
The interpolation routine recognizes strict kinds passed as names of
inflection options in almost the same way that it does for regular
kinds. The only difference is that you can override usage
of a regular kind inflection option (if there is any) by
putting a strict kind option with the same name but prefixed by +@+ symbol.
The inflection options starting with this symbol have
precedence over inflection options without it;
that is of course only true for strict kinds and has any effect
only when both options describing kinds of the same name are present.
In other words: interpolation routine is looking for
strict kinds in inflection options using their names
with +@+ in front. When that fails it falls back to
an option named like the strict kind but without
the +@+ symbol. Examples:
I18n.translate(welcome, :gender => :m, :@gender => :f)
# the :f will be picked for the strict kind gender
I18n.translate(welcome, :@gender => :f)
# the :f will be picked for the strict kind gender
I18n.translate(welcome, :gender => :f)
# the :f will be picked for the strict kind gender
In the example above we assume that +welcome+ is defined
like that:
welcome: "Dear @gender{f:Madam|m:Sir|n:You|All}"
Note that for regular kinds the option named +:@gender+
will have no meaning.
==== Note for developers
Strict kinds that are used to handle named patterns
are internally stored in a different database and handled by
similar but different API methods than regular kinds. However
most of the {I18n::Inflector::API} methods are also aware of strict kinds
and will call proper methods oprating on strict inflections
data when the +@+ symbol is detected at the beginning of
the identifier of a kind passed as an argument. For example:
I18n.inflector.has_token?(:m, :@gender)
will effectively call:
I18n.inflector.strict.has_token?(:m, :gender)
As you can see above, to access {API_Strict} methods for strict kinds
(and strict kinds data) only, associated with default I18n backend,
use:
I18n.inflector.strict
== Multiple patterns
You can make use of some syntactic sugar when having more than
one pattern (regular or named) in your string. To not repeat
a kind identifier(s) you may join pattern contents as in the
following example:
welcome: "You are @gender{f:pretty|m,n:handsome}{ }{f:lady|m:sir|n:human}"
As you can see there should be no spaces or any other characters
between successive patterns. That's why in this example an
empty pattern content is used. This is in fact a pattern
containing no tokens but just a free text consisting
of single space character.
== Complex patterns
A complex pattern is a named pattern that uses more than
one inflection kind and sets of a respective tokens. The given identifiers
of kinds should be separated by the plus sign and instead of single
tokens there should be token sets (a tokens separated by the plus
sign too).
Example:
welcome: "Dear @gender+number{f+s:Lady|f+p:Ladies|m+s:Sir|m+p:Gentlemen|All}"
In the example above the complex pattern uses +gender+ and +number+
inflection kinds and a token set (e.g. f+s) matches when
both tokens match interpolation options (e.g. :gender => :f,
:number => :s). The order of tokens in sets has meaning
and should reflect the order of declared kinds.
Note, that the count of tokens in each set should reflect the count
of kinds that are used. Otherwise the interpolation routine will
interpolate a free text (if given) or an empty string. If the switch
{InflectionOptions#raises} is on then the {I18n::ComplexPatternMalformed}
exception will be raised.
The inflection tokens used in sets may make use of any features mentioned
before (defaults, excluded defaults, negative matching, token groups,
aliases, aliased patterns, loud tokens, wildcards).
=== Loud tokens in complex patterns
In case of loud tokens (having values taken from their
descriptions), the complex pattern will be replaced by
the descriptions of matching tokens joined with a single space
character. So, for instance, when the translation data looks like:
i18n:
inflections:
@person:
i: 'I'
u: 'You'
@tense:
now: 'am'
past: 'were'
welcome: "@person+tense{i+now:~|u+past:~}"
the translate method will give the following results:
I18n.translate('welcome', :person => :i, :tense => :now)
# => "I am"
I18n.translate('welcome', :person => :you, :tense => :past)
# => "You were"
This example is abstract, since the combination of +:i+
and +:past+ will result in i were string, which is
probably something unexpected. To achieve that kind of logic
simply use combined patterns with the given values instead
of loud tokens.
=== Wildcard tokens in complex patterns
The wildcard tokens might be extremely helpful in complex
patterns since there is one shared free text for a whole pattern
yet there might be a need to match any token for some subkind.
For example:
welcome: @person+tense{i+present:am|u+present:are|*+present:is}
Note that in the example above +*+ matches 'i', 'you', 'he', 'she' and 'it'
but 'i' and 'u' are effectively matched before. The equivalent pattern without
a wildcard token would look like:
welcome: @person+tense{i+present:am|u+present:are|i,u,he,she,it+present:is}
== Inflection keys
There is a way of storing inflected strings in keys instead
of patterns. To use it you should simply assign subkeys to
some translation key instead of string containing a pattern.
The key-based inflection group is contained within a key
which name begins with the +@+ symbol.
The translation key containing a pattern:
welcome: "Dear @{f:Lady|m:Sir|n:You|All}!"
Can be easily written as:
@welcome:
f: "Lady"
m: "Sir"
n: "You"
@free: "All"
@prefix: "Dear "
@suffix: "!"
You can also use strict kind or even the inflection sets, token
groups, etc.:
welcome: "@gender+tense{f+past:She was|m+present:He is|n+future:You will be}"
Can be written as:
@welcome:
f+past: "She was"
m+present: "He is"
n+future: "You will be"
@kind: "gender+tense"
There are special, optional subkeys that may give you
more control over inflection process. These are:
* +@kind+: a kind or kinds in case of strict kinds
* +@prefix+: a prefix to be put before the interpolated data
* +@suffix+: a suffix to be put after the interpolated data
* +@free+: a free text that is to be used when no token will match
=== Limitations
Inflection keys look compact and clean but obviously
you cannot use the key-based inflection to simply replace
a string containing more than one inflection pattern.
Also, you have to be very careful when using this method
with Ruby 1.8 because the order of processed token sets
may change. That may break the logic in case of inflection
sets where order has meaning (e.g. tokens with inverted
matching).
== Errors
By default the module will silently ignore non-critical interpolation
errors. You can turn off this default behavior by passing +:inflector_raises+
option set to +true+. Note that most errors is reported because of
wrong data in patterns or in configuration. In case of inflection
options only malformed, empty or +nil+ values are reported
when the mentioned switch is turned on. For inflection options
containing unknown tokens no errors are generated.
=== Usage of +:inflector_raises+ option
*YAML:*
Note: Uses inflection configuration given in the first example.
en:
welcome: "Dear @{m:Sir|f:Madam|Fallback}"
*Code:*
I18n.t('welcome', :inflector_raises => true)
# => I18n::InflectionOptionNotFound: en.welcome:
# @{m:Sir|f:Madam|Fallback}" - required option :gender was not found
=== Exception meanings
Here are the exceptions that may be raised when the option +:inflector_raises+
is set to +true+:
* {I18n::InvalidInflectionToken I18n::InvalidInflectionToken}
* {I18n::InvalidInflectionKind I18n::InvalidInflectionKind}
* {I18n::InvalidInflectionOption I18n::InvalidInflectionOption}
* {I18n::MisplacedInflectionToken I18n::MisplacedInflectionToken}
* {I18n::InflectionOptionNotFound I18n::InflectionOptionNotFound}
* {I18n::InflectionOptionIncorrect I18n::InflectionOptionIncorrect}
* {I18n::ComplexPatternMalformed I18n::ComplexPatternMalformed}
There are also exceptions that are raised regardless of :+inflector_raises+
presence or value.
These are usually caused by critical errors encountered during processing
inflection data or exceptions raised by I18n. Note that the pure I18n's
exceptions are not described here.
* {I18n::ArgumentError I18n::ArgumentError}
* {I18n::InvalidLocale I18n::InvalidLocale}
* {I18n::DuplicatedInflectionToken I18n::DuplicatedInflectionToken}
* {I18n::BadInflectionKind I18n::BadInflectionKind}
* {I18n::BadInflectionToken I18n::BadInflectionToken}
* {I18n::BadInflectionAlias I18n::BadInflectionAlias}
=== Exception hierarchy
I18n::ArgumentError
|
`-- I18n::InvalidLocale
|
`-- I18n::InflectionException
|
`-- I18n::InflectionPatternException
| |
| |-- I18n::InvalidInflectionToken
| |-- I18n::InvalidInflectionKind
| |-- I18n::MisplacedInflectionToken
| |-- I18n::ComplexPatternMalformed
| `-- I18n::InvalidOptionForKind
| |-- I18n::InflectionOptionNotFound
| `-- I18n::InflectionOptionIncorrect
|
`-- I18n::InflectionConfigurationException
|
|-- I18n::DuplicatedInflectionToken
|-- I18n::BadInflectionAlias
|-- I18n::BadInflectionToken
`-- I18n::BadInflectionKind
== Reserved names and characters
Some strings cannot be used as names and/or identifiers of
kinds and tokens. There are also some reserved characters
that cannot be used within them.
=== Reserved keys
Reserved keys, that cannot be used as names of inflection
options and as names of kinds in the configuration
are available after issuing:
I18n::Inflector::Config::Reserved::KEYS.to_a
Here is the current list: :scope, :default, :separator,
:resolve, :object, :fallback, :format, :cascade,
:raise, :rescue_format, :inflector_cache_aware,
:inflector_raises, :inflector_aliased_patterns,
:inflector_unknown_defaults, :inflector_excluded_defaults.
Additionally all Symbols or Strings beginning with
+inflector_+ are prohibited, since they are reserved as
controlling options.
=== Reserved characters
All characters that have special meaning (operators and
markers) are not allowed in patterns, in configuration
and in options.
==== Reserved characters in kinds
===== Passed as inflection options
* *Constant:* {I18n::Inflector::Config::Reserved::Kinds::OPTION}
* *List:* + | : ! { } and , (comma).
===== Given in a configuration
* *Constant:* {I18n::Inflector::Config::Reserved::Kinds::DB}
* *List:* + | : ! { } and , (comma).
===== Placed in patterns
* *Constant:* {I18n::Inflector::Config::Reserved::Kinds::PATTERN}
* *List:* + | : , ! @ { } and , (comma).
==== Reserved characters in tokens
===== Passed as values of inflection options
* *Constant:* {I18n::Inflector::Config::Reserved::Tokens::OPTION}
* *List:* * + | : ! @ { } and , (comma).
===== Given in a configuration
* *Constant:* {I18n::Inflector::Config::Reserved::Tokens::DB}
* *List:* * + | : ! @ { } and , (comma).
===== Placed in patterns
* *Constant:* {I18n::Inflector::Config::Reserved::Tokens::PATTERN}
* *List:* + | : ! @ { } and , (comma).
== Operators and markers
Here is more formal definition of operators and markers used in patterns.
=== Pattern
@[kind][+kind ...]{token_set[|token_set ...][|free_text]}
* +@+ is the pattern marker
* +{+ and +}+ are pattern delimiters
* +free_text+ is an optional free text value
* +kind+ is a kind identifier
* + is the +AND+ operator that joins kinds (produces complex kinds)
==== +token_set+
*|token_group[+token_group ...]:value
* +:+ is the +ASSIGNMENT+ operator
* +value+ is a value to be picked up then a token set matches; value may also
be the loud marker (+~+)
* + is the +AND+ operator that joins many token groups into a set
* +*+ is the +WILDCARD+ operator
===== +token_group+
[!]token[,[!]token ...]
* +token+ is a token identifier
* +!+ is the +NOT+ operator
* +,+ is the +OR+ operator
=== Operator precedence
* Single token level
* +NOT+ operators for inversed matching of tokens (!)
* +OR+ operators for joining tokens into token groups (,)
* Token group level
* +WILDCARD+ operators for matching any token (*)
* +AND+ operators for joining token groups into sets (+)
* Token set level
* +ASSIGNMENT+ operators for assigning values to token sets (:)
* +OR+ operators for separating token sets and/or free texts (|)
* Pattern name level
* +AND+ operators for kind identifiers (+)
* Pattern level
* Pattern marker and pattern delimiters
== Classes and relations
=== Library contents
* Module {I18n::Inflector} containing everything
* Class {I18n::Inflector::API} used to create inflector object attached to I18n backend (handles regular and strict kinds)
* Class {I18n::Inflector::API_Strict} which instance is attached to {I18n::Inflector::API} and handles strict kinds
* Class {I18n::Inflector::InflectionData} used to store inflection data for regular kinds and tokens
* Class {I18n::Inflector::InflectionData_Strict} used to store inflection data for strict kinds and tokens
* Class {I18n::Inflector::InflectionOptions} used for keeping switches and options
* Class {I18n::Inflector::LazyHashEnumerator} used to manage lazy evaluation of internal data
* Module {I18n::Backend::Inflector} used to alter methods of {I18n::Backend::Simple}
* Several classes for error reporting
=== Relations
* {I18n.backend} is the currently used backend and the instance of {I18n::Backend::Simple}
* {I18n.backend.inflector} is the instance of {I18n::Inflector::API} attached to backend
* {I18n.inflector} is the proxy module method that calls inflector for currently used backend {I18n.backend.inflector}
* {I18n.backend.inflector.options} is the instance of {I18n::Inflector::InflectionOptions} and
mainly it controls a behavior of interpolation method
* {I18n.backend.inflector.strict} is the instance of {I18n::Inflector::API_Strict} and handles strict kinds
* {I18n.backend.inflector} uses {I18n.backend.inflector.strict} to access strict kinds when it's needed
* {I18n::Inflector::API} has an instance variable @idb that contains database of inflections indexed by locale
* {I18n::Inflector::API_Strict} has an instance variable @idb that contains database of inflections indexed by locale
* Translation databases are kind of {I18n::Inflector::InflectionData} and {I18n::Inflector::InflectionData_Strict}
* When initializing translations a method from {I18n::Backend::Simple} (altered by {I18n::Backend::Inflector})
takes the loaded data, processes their i18n.inflections scope for each locale and creates database
objects which are kind of {I18n::Inflector::InflectionData} and {I18n::Inflector::InflectionData_Strict}. That
objects are then attached to instances of {I18n::Inflector::API} and {I18n::Inflector::API_Strict}.
i18n-inflector-2.6.7/test/ 0000755 0000041 0000041 00000000000 13321144047 015276 5 ustar www-data www-data i18n-inflector-2.6.7/test/inflector_test.rb 0000644 0000041 0000041 00000147752 13321144047 020667 0 ustar www-data www-data require 'test_helper'
class I18nInflectorTest < Test::Unit::TestCase
class Backend < I18n::Backend::Simple
include I18n::Backend::Inflector
include I18n::Backend::Fallbacks
end
def setup
I18n.backend = Backend.new
store_translations(:xx, :i18n => { :inflections => {
:gender => {
:m => 'male',
:f => 'female',
:n => 'neuter',
:s => 'strange',
:masculine => '@m',
:feminine => '@f',
:neuter => '@n',
:neutral => '@neuter',
:default => 'neutral' },
:person => {
:i => 'I',
:you => 'You'},
:@gender => {
:m => 'male',
:f => 'female',
:n => 'neuter',
:s => 'strange',
:masculine => '@m',
:feminine => '@f',
:neuter => '@n',
:neutral => '@neuter',
:default => 'neutral' }
} })
store_translations(:xx, 'welcome' => 'Dear @{f:Lady|m:Sir|n:You|All}!')
store_translations(:xx, 'named_welcome' => 'Dear @gender{f:Lady|m:Sir|n:You|All}!')
I18n.locale = :en
end
test "backend inflector has methods to test its switches" do
assert_equal true, I18n.inflector.options.unknown_defaults = true
assert_equal false, I18n.inflector.options.excluded_defaults = false
assert_equal false, I18n.inflector.options.aliased_patterns = false
assert_equal false, I18n.inflector.options.raises = false
assert_equal false, I18n.backend.inflector.options.raises
assert_equal true, I18n.backend.inflector.options.unknown_defaults
assert_equal false, I18n.backend.inflector.options.excluded_defaults
assert_equal false, I18n.backend.inflector.options.aliased_patterns
end
test "backend inflector store_translations: regenerates inflection structures when translations are loaded" do
store_translations(:xx, :i18n => { :inflections => { :gender => { :o => 'other' }}})
store_translations(:xx, 'hi' => 'Dear @{f:Lady|o:Others|n:You|All}!')
assert_equal 'Dear Others!', I18n.t('hi', :gender => :o, :locale => :xx)
assert_equal 'Dear Lady!', I18n.t('hi', :gender => :f, :locale => :xx)
assert_equal 'Dear You!', I18n.t('hi', :gender => :unknown, :locale => :xx)
assert_equal 'Dear All!', I18n.t('hi', :gender => :m, :locale => :xx)
end
test "backend inflector store_translations: raises I18n::DuplicatedInflectionToken when duplicated token is given" do
assert_raise I18n::DuplicatedInflectionToken do
store_translations(:xx, :i18n => { :inflections => { :gender => { :o => 'other' }, :person => { :o => 'o' }}})
end
end
test "backend inflector strict store_translations: allows duplicated tokens across differend kinds" do
assert_nothing_raised I18n::DuplicatedInflectionToken do
store_translations(:xx, :i18n => { :inflections => { :@gender => { :o => 'other' }, :@person => { :o => 'o' }}})
store_translations(:xx, :i18n => { :inflections => { :gender => { :o => 'other' }, :@gender => { :o => 'o' }}})
end
end
test "backend inflector store_translations: raises I18n::BadInflectionAlias when bad alias is given" do
assert_raise I18n::BadInflectionAlias do
store_translations(:xx, :i18n => { :inflections => { :gender => { :o => '@xnonexistant' }}})
end
end
test "backend inflector store_translations: raises I18n::BadInflectionAlias when bad default is given" do
assert_raise I18n::BadInflectionAlias do
store_translations(:xx, :i18n => { :inflections => { :gender => { :default => '@ynonexistant' }}})
end
end
test "backend inflector strict store_translations: raises I18n::BadInflectionAlias when bad alias is given" do
assert_raise I18n::BadInflectionAlias do
store_translations(:xx, :i18n => { :inflections => { :@gender => { :oh => '@znonex' }}})
end
end
test "backend inflector strict store_translations: raises I18n::BadInflectionAlias when bad default is given" do
assert_raise I18n::BadInflectionAlias do
store_translations(:xx, :i18n => { :inflections => { :@gender => { :default => '@cnonex' }}})
end
end
test "backend inflector store_translations: raises I18n::BadInflectionToken when bad token is given" do
assert_raise I18n::BadInflectionToken do
store_translations(:xx, :i18n => { :inflections => { :gender => { :o => '@' }}})
store_translations(:xx, :i18n => { :inflections => { :gender => { :tok => nil }}})
store_translations(:xx, :i18n => { :inflections => { :@gender => { :o => '@' }}})
store_translations(:xx, :i18n => { :inflections => { :@gender => { :tok => nil }}})
end
end
test "backend inflector translate: allows pattern-only translation data" do
store_translations(:xx, 'clear_welcome' => '@{f:Lady|m:Sir|n:You|All}')
assert_equal 'Lady', I18n.t('clear_welcome', :gender => 'f', :locale => :xx)
store_translations(:xx, 'clear_welcome' => '@gender{f:Lady|m:Sir|n:You|All}')
assert_equal 'Lady', I18n.t('clear_welcome', :gender => 'f', :locale => :xx)
end
test "backend inflector translate: allows patterns to be escaped using @@ or \\@" do
store_translations(:xx, 'escaped_welcome' => '@@{f:AAAAA|m:BBBBB}')
assert_equal '@{f:AAAAA|m:BBBBB}', I18n.t('escaped_welcome', :gender => 'f', :locale => :xx)
store_translations(:xx, 'escaped_welcome' => '\@{f:AAAAA|m:BBBBB}')
assert_equal '@{f:AAAAA|m:BBBBB}', I18n.t('escaped_welcome', :gender => 'f', :locale => :xx)
assert_equal 'Dear All!', I18n.t('welcome', :gender => nil, :locale => :xx, :inflector_unknown_defaults => false)
store_translations(:xx, 'escaped_welcome' => 'Dear \@{f:Lady|m:Sir|n:You|All}!');
assert_equal 'Dear @{f:Lady|m:Sir|n:You|All}!', I18n.t('escaped_welcome', :locale => :xx, :inflector_unknown_defaults => false)
end
test "backend inflector translate: picks Lady for :f gender option" do
assert_equal 'Dear Lady!', I18n.t('welcome', :gender => :f, :locale => :xx)
end
test "backend inflector translate: picks Lady for f gender option" do
assert_equal 'Dear Lady!', I18n.t('welcome', :gender => 'f', :locale => :xx)
end
test "backend inflector translate: picks Sir for :m gender option" do
assert_equal 'Dear Sir!', I18n.t('welcome', :gender => :m, :locale => :xx)
end
test "backend inflector translate: picks Sir for :masculine gender option" do
assert_equal 'Dear Sir!', I18n.t('welcome', :gender => :masculine, :locale => :xx)
end
test "backend inflector translate: picks Sir for masculine gender option" do
assert_equal 'Dear Sir!', I18n.t('welcome', :gender => 'masculine', :locale => :xx)
end
test "backend inflector translate: picks an empty string when no default token is present and no free text is there" do
store_translations(:xx, 'none_welcome' => '@{n:You|f:Lady}')
assert_equal '', I18n.t('none_welcome', :gender => 'masculine', :locale => :xx)
end
test "backend inflector translate: allows multiple patterns in the same data" do
store_translations(:xx, 'multiple_welcome' => '@@{f:AAAAA|m:BBBBB} @{f:Lady|m:Sir|n:You|All} @{f:Lady|All}@{m:Sir|All}@{n:You|All}')
assert_equal '@{f:AAAAA|m:BBBBB} Sir AllSirAll', I18n.t('multiple_welcome', :gender => 'masculine', :locale => :xx)
end
test "backend inflector translate: falls back to default for the unknown gender option" do
assert_equal 'Dear You!', I18n.t('welcome', :gender => :unknown, :locale => :xx)
end
test "backend inflector translate: falls back to default for a gender option set to nil" do
assert_equal 'Dear You!', I18n.t('welcome', :gender => nil, :locale => :xx)
end
test "backend inflector translate: falls back to default for no gender option" do
assert_equal 'Dear You!', I18n.t('welcome', :locale => :xx)
end
test "backend inflector translate: falls back to free text for the proper gender option but not present in pattern" do
assert_equal 'Dear All!', I18n.t('welcome', :gender => :s, :locale => :xx)
end
test "backend inflector translate: falls back to free text when :inflector_unknown_defaults is false" do
assert_equal 'Dear All!', I18n.t('welcome', :gender => :unknown, :locale => :xx, :inflector_unknown_defaults => false)
assert_equal 'Dear All!', I18n.t('welcome', :gender => :s, :locale => :xx, :inflector_unknown_defaults => false)
assert_equal 'Dear All!', I18n.t('welcome', :gender => nil, :locale => :xx, :inflector_unknown_defaults => false)
end
test "backend inflector translate: uses default token when inflection option is set to :default" do
assert_equal 'Dear You!', I18n.t('welcome', :gender => :default, :locale => :xx, :inflector_unknown_defaults => true)
assert_equal 'Dear You!', I18n.t('welcome', :gender => :default, :locale => :xx, :inflector_unknown_defaults => false)
end
test "backend inflector translate: falls back to default for no inflection option when :inflector_unknown_defaults is false" do
assert_equal 'Dear You!', I18n.t('welcome', :locale => :xx, :inflector_unknown_defaults => false)
end
test "backend inflector translate: falls back to free text for the unknown gender option when global inflector_unknown_defaults is false" do
I18n.inflector.options.unknown_defaults = false
assert_equal 'Dear All!', I18n.t('welcome', :gender => :unknown, :locale => :xx)
end
test "backend inflector translate: falls back to default for the unknown gender option when global inflector_unknown_defaults is overriden" do
I18n.inflector.options.unknown_defaults = false
assert_equal 'Dear You!', I18n.t('welcome', :gender => :unknown, :locale => :xx, :inflector_unknown_defaults => true)
end
test "backend inflector translate: falls back to default token for ommited gender option when :inflector_excluded_defaults is true" do
assert_equal 'Dear You!', I18n.t('welcome', :gender => :s, :locale => :xx, :inflector_excluded_defaults => true)
assert_equal 'Dear You!', I18n.t('named_welcome', :@gender => :s, :locale => :xx, :inflector_excluded_defaults => true)
I18n.inflector.options.excluded_defaults = true
assert_equal 'Dear You!', I18n.t('welcome', :gender => :s, :locale => :xx)
assert_equal 'Dear You!', I18n.t('named_welcome', :gender => :s, :locale => :xx)
end
test "backend inflector translate: falls back to free text for ommited gender option when :inflector_excluded_defaults is false" do
assert_equal 'Dear All!', I18n.t('welcome', :gender => :s, :locale => :xx, :inflector_excluded_defaults => false)
I18n.inflector.options.excluded_defaults = false
assert_equal 'Dear All!', I18n.t('welcome', :gender => :s, :locale => :xx)
end
test "backend inflector translate: raises I18n::InvalidOptionForKind when bad kind is given and inflector_raises is true" do
assert_nothing_raised I18n::InvalidOptionForKind do
I18n.t('welcome', :locale => :xx, :inflector_raises => true)
end
tr = I18n.backend.send(:translations)
tr[:xx][:i18n][:inflections][:gender].delete(:default)
store_translations(:xx, :i18n => { :inflections => { :gender => { :o => 'other' }}})
assert_raise(I18n::InflectionOptionNotFound) { I18n.t('welcome', :locale => :xx, :inflector_raises => true) }
assert_raise(I18n::InvalidInflectionOption) { I18n.t('welcome', :locale => :xx, :gender => "", :inflector_raises => true) }
assert_raise(I18n::InvalidInflectionOption) { I18n.t('welcome', :locale => :xx, :gender => nil, :inflector_raises => true) }
assert_raise I18n::InflectionOptionNotFound do
I18n.inflector.options.raises = true
I18n.t('welcome', :locale => :xx)
end
end
test "backend inflector translate: raises I18n::MisplacedInflectionToken when misplaced token is given and inflector_raises is true" do
store_translations(:xx, 'hi' => 'Dear @{f:Lady|i:BAD_TOKEN|n:You|First}!')
assert_raise(I18n::MisplacedInflectionToken) { I18n.t('hi', :locale => :xx, :inflector_raises => true) }
assert_raise I18n::MisplacedInflectionToken do
I18n.inflector.options.raises = true
I18n.t('hi', :locale => :xx)
end
end
test "backend inflector translate: raises I18n::MisplacedInflectionToken when bad token is given and inflector_raises is true" do
store_translations(:xx, 'hi' => 'Dear @{f:Lady|i:Me|n:You|First}!')
assert_raise(I18n::MisplacedInflectionToken) { I18n.t('hi', :locale => :xx, :inflector_raises => true) }
assert_raise I18n::MisplacedInflectionToken do
I18n.inflector.options.raises = true
I18n.t('hi', :locale => :xx)
end
end
test "backend inflector translate: works with %{} patterns" do
store_translations(:xx, 'hi' => 'Dear @{f:Lady|m:%{test}}!')
assert_equal 'Dear Dude!', I18n.t('hi', :gender => :m, :locale => :xx, :test => "Dude")
store_translations(:xx, 'to be' => '%{person} @{i:am|you:are}')
assert_equal 'you are', I18n.t('to be', :person => :you, :locale => :xx)
end
test "backend inflector translate: works with doubled patterns" do
store_translations(:xx, 'dd' => 'Dear @{f:Lady|m:Sir|All}! Dear @{f:Lady|m:Sir|All}!')
assert_equal 'Dear Lady! Dear Lady!', I18n.t('dd', :gender => :f, :locale => :xx)
store_translations(:xx, 'hi' => 'Dear @{f:Lady|m:%{test}}! Dear @{f:Lady|m:%{test}}!')
assert_equal 'Dear Dude! Dear Dude!', I18n.t('hi', :gender => :m, :locale => :xx, :test => "Dude")
end
test "backend inflector translate: works with complex patterns" do
store_translations(:xx, :i18n => { :inflections => { :@tense => { :s => 's', :now => 'now', :past => 'later', :default => 'now' }}})
store_translations(:xx, 'hi' => '@gender+tense{m+now:he is|f+past:she was} here!')
assert_equal 'he is here!', I18n.t('hi', :gender => :m, :locale => :xx, :inflector_raises => true)
assert_equal 'he is here!', I18n.t('hi', :gender => :m, :locale => :xx, :inflector_raises => true)
assert_equal 'he is here!', I18n.t('hi', :gender => :m, :tense => :s, :locale => :xx, :inflector_excluded_defaults => true)
assert_equal 'she was here!', I18n.t('hi', :gender => :f, :tense => :past, :locale => :xx, :inflector_raises => true)
assert_equal 'she was here!', I18n.t('hi', :gender => :feminine, :tense => :past, :locale => :xx, :inflector_raises => true)
store_translations(:xx, 'hi' => '@gender+tense{masculine+now:he is|feminine+past:she was}')
assert_equal 'he is', I18n.t('hi', :gender => :m, :tense => :now, :inflector_aliased_patterns => true, :locale => :xx)
assert_equal 'she was', I18n.t('hi', :gender => :f, :tense => :past, :inflector_aliased_patterns => true, :locale => :xx)
store_translations(:xx, 'hi' => '@gender+tense{masculine+now:he is|feminine+past:she was}')
assert_equal 'she was', I18n.t('hi', :gender => :f, :tense => :past, :inflector_aliased_patterns => true, :locale => :xx)
store_translations(:xx, 'hi' => '@gender+tense{masculine+now:he is|feminine+past:she was}')
assert_equal 'she was', I18n.t('hi', :gender => :feminine, :tense => :past, :inflector_aliased_patterns => true, :locale => :xx)
store_translations(:xx, 'hi' => '@gender+tense{masculine+now:he is|m+past:he was}')
assert_equal 'he was', I18n.t('hi', :gender => :m, :tense => :past, :inflector_aliased_patterns => true, :locale => :xx)
store_translations(:xx, 'hi' => '@gender+tense{m+now:he is|masculine+past:he was}')
assert_equal 'he was', I18n.t('hi', :gender => :m, :tense => :past, :inflector_aliased_patterns => true, :locale => :xx)
store_translations(:xx, 'hi' => '@gender+tense{m+now:~|f+past:she was}')
assert_equal 'male now', I18n.t('hi', :gender => :m, :tense => :now, :locale => :xx)
end
test "backend inflector translate: works with multiple patterns" do
store_translations(:xx, 'hi' => '@gender{m:Sir|f:Lady}{m: Lancelot|f: Morgana}')
assert_equal 'Sir Lancelot', I18n.t('hi', :gender => :m, :locale => :xx)
assert_equal 'Lady Morgana', I18n.t('hi', :gender => :f, :locale => :xx)
store_translations(:xx, 'hi' => '@{m:Sir|f:Lady}{m: Lancelot|f: Morgana}')
assert_equal 'Sir Lancelot', I18n.t('hi', :gender => :m, :locale => :xx)
assert_equal 'Lady Morgana', I18n.t('hi', :gender => :f, :locale => :xx)
store_translations(:xx, 'hi' => 'Hi @{m:Sir|f:Lady}{m: Lancelot|f: Morgana}!')
assert_equal 'Hi Sir Lancelot!', I18n.t('hi', :gender => :m, :locale => :xx)
end
test "backend inflector translate: works with key-based inflections" do
I18n.backend.store_translations(:xx, '@hi' => { :m => 'Sir', :f => 'Lady', :n => 'You',
:@free => 'TEST', :@prefix => 'Dear ', :@suffix => '!' })
assert_equal 'Dear Sir!', I18n.t('@hi', :gender => :m, :locale => :xx, :inflector_raises=>true)
assert_equal 'Dear Lady!', I18n.t('@hi', :gender => :f, :locale => :xx, :inflector_raises=>true)
assert_equal 'Dear TEST!', I18n.t('@hi', :gender => :x, :locale => :xx, :inflector_unknown_defaults => false)
assert_equal 'Dear TEST!', I18n.t('@hi', :gender => :x, :locale => :xx, :inflector_unknown_defaults => false)
end
test "backend inflector translate: raises I18n::ComplexPatternMalformed for malformed complex patterns" do
store_translations(:xx, :i18n => { :inflections => { :@tense => { :now => 'now', :past => 'later', :default => 'now' }}})
store_translations(:xx, 'hi' => '@gender+tense{m+now+cos:he is|f+past:she was} here!')
assert_raise I18n::ComplexPatternMalformed do
I18n.t('hi', :gender => :m, :person => :you, :locale => :xx, :inflector_raises => true)
end
store_translations(:xx, 'hi' => '@gender+tense{m+:he is|f+past:she was} here!')
assert_raise I18n::ComplexPatternMalformed do
I18n.t('hi', :gender => :m, :person => :you, :locale => :xx, :inflector_raises => true)
end
store_translations(:xx, 'hi' => '@gender+tense{+:he is|f+past:she was} here!')
assert_raise I18n::ComplexPatternMalformed do
I18n.t('hi', :gender => :m, :person => :you, :locale => :xx, :inflector_raises => true)
end
store_translations(:xx, 'hi' => '@gender+tense{m:he is|f+past:she was} here!')
assert_raise I18n::ComplexPatternMalformed do
I18n.t('hi', :gender => :m, :person => :you, :locale => :xx, :inflector_raises => true)
end
end
test "backend inflector translate: works with wildcard tokens" do
store_translations(:xx, 'hi' => 'Dear @{n:You|*:Any|All}!')
assert_equal 'Dear You!', I18n.t('hi', :gender => :n, :locale => :xx)
assert_equal 'Dear Any!', I18n.t('hi', :gender => :m, :locale => :xx)
assert_equal 'Dear Any!', I18n.t('hi', :gender => :f, :locale => :xx)
assert_equal 'Dear You!', I18n.t('hi', :gender => :xxxxxx, :locale => :xx)
assert_equal 'Dear You!', I18n.t('hi', :locale => :xx)
end
test "backend inflector translate: works with loud tokens" do
store_translations(:xx, 'hi' => 'Dear @{m:~|n:You|All}!')
assert_equal 'Dear male!', I18n.t('hi', :gender => :m, :locale => :xx)
store_translations(:xx, 'hi' => 'Dear @gender{m:~|n:You|All}!')
assert_equal 'Dear male!', I18n.t('hi', :gender => :m, :locale => :xx)
store_translations(:xx, 'hi' => 'Dear @{masculine:~|n:You|All}!')
assert_equal 'Dear male!', I18n.t('hi', :gender => :m, :locale => :xx, :inflector_aliased_patterns => true)
store_translations(:xx, 'hi' => 'Dear @{f,m:~|n:You|All}!')
assert_equal 'Dear male!', I18n.t('hi', :gender => :m, :locale => :xx)
store_translations(:xx, 'hi' => 'Dear @{!n:~|n:You|All}!')
assert_equal 'Dear male!', I18n.t('hi', :gender => :m, :locale => :xx)
store_translations(:xx, 'hi' => 'Dear @{!n:\~|n:You|All}!')
assert_equal 'Dear ~!', I18n.t('hi', :gender => :m, :locale => :xx)
store_translations(:xx, 'hi' => 'Dear @{!n:\\\\~|n:You|All}!')
assert_equal 'Dear \\~!', I18n.t('hi', :gender => :m, :locale => :xx)
store_translations(:xx, 'hi' => 'Dear @{*:~|n:You|All}!')
assert_equal 'Dear male!', I18n.t('hi', :gender => :m, :locale => :xx)
store_translations(:xx, 'hi' => 'Dear @{*:~|n:You|All}!')
assert_equal 'Dear neuter!', I18n.t('hi', :locale => :xx)
store_translations(:xx, 'hi' => 'Dear @{m:abc|*:~|n:You|All}!')
assert_equal 'Dear neuter!', I18n.t('hi', :locale => :xx)
store_translations(:xx, 'hi' => 'Dear @{*:~|All}!')
assert_equal 'Dear All!', I18n.t('hi', :gender => :unasdasd, :locale => :xx)
store_translations(:xx, 'hi' => 'Dear @{*:~|All}!')
assert_equal 'Dear All!', I18n.t('hi', :gender => nil, :locale => :xx)
store_translations(:xx, 'hi' => 'Dear @{*:~|All}!')
assert_equal 'Dear neuter!', I18n.t('hi', :gender => :n, :locale => :xx)
store_translations(:xx, :i18n => { :inflections => { :@tense => { :s => 's', :now => 'now', :past => 'later', :default => 'now' }}})
store_translations(:xx, 'hi' => 'Dear @gender+tense{*+*:~|All}!')
assert_equal 'Dear male now!', I18n.t('hi', :gender => :m, :person => :i, :locale => :xx)
assert_equal 'Dear neuter now!', I18n.t('hi', :locale => :xx)
assert_equal 'Dear neuter later!', I18n.t('hi', :tense => :past, :locale => :xx)
end
test "backend inflector translate: works with tokens separated by commas" do
store_translations(:xx, 'hi' => 'Dear @{f,m:Someone|n:You|All}!')
assert_equal 'Dear Someone!', I18n.t('hi', :gender => :m, :locale => :xx)
end
test "backend inflector translate: works with collections" do
h = Hash.new
h[:hi2] = h[:hi] = "Dear Someone!"
store_translations(:xx, 'welcomes' => {'hi' => 'Dear @{f,m:Someone|n:You|All}!', 'hi2' => 'Dear @{f,m:Someone|n:You|All}!'})
assert_equal h, I18n.t('welcomes', :gender => :m, :foo => 5, :locale => :xx)
end
test "backend inflector translate: works with arrays as results" do
a = [ :one, :two, :three ]
store_translations(:xx, 'welcomes' => {'hi' => a})
store_translations(:uu, 'welcomes' => {'hi' => a})
assert_equal a, I18n.t('welcomes.hi', :gender => :m, :locale => :xx)
assert_equal a, I18n.t('welcomes.hi', :gender => :m, :locale => :uu)
a = [ :one, :two, :"x@{m:man|woman}d" ]
store_translations(:xx, 'welcomes' => {'hi' => a})
store_translations(:uu, 'welcomes' => {'hi' => a})
assert_equal a, I18n.t('welcomes.hi', :gender => :m, :locale => :xx)
assert_equal a, I18n.t('welcomes.hi', :gender => :m, :locale => :uu)
a = [ :one, :two, :xmand ]
assert_equal a, I18n.t('welcomes.hi', :gender => :m, :locale => :xx, :inflector_interpolate_symbols => true)
a = [ :one, :two, :xd ]
assert_equal a, I18n.t('welcomes.hi', :gender => :m, :locale => :uu, :inflector_interpolate_symbols => true)
a = [ :one, :two, :"x@{m:man|woman}d" ]
assert_equal a, I18n.t('welcomes.hi', :gender => :m, :locale => :xx, :inflector_traverses => false, :inflector_interpolate_symbols => true)
a = [ :one, :two, :"x@{m:man|woman}d" ]
assert_equal a, I18n.t('welcomes.hi', :gender => :m, :locale => :uu, :inflector_traverses => false, :inflector_interpolate_symbols => true)
end
test "backend inflector translate: works with other types as results" do
store_translations(:xx, 'welcomes' => {'hi' => 31337})
assert_equal 31337, I18n.t('welcomes.hi', :gender => :m, :locale => :xx)
end
test "backend inflector translate: works with negative tokens" do
store_translations(:xx, 'hi' => 'Dear @{!m:Lady|m:Sir|n:You|All}!')
assert_equal 'Dear Lady!', I18n.t('hi', :gender => :n, :locale => :xx)
assert_equal 'Dear Sir!', I18n.t('hi', :gender => :m, :locale => :xx)
assert_equal 'Dear Lady!', I18n.t('hi', :locale => :xx)
assert_equal 'Dear Lady!', I18n.t('hi', :gender => :unknown, :locale => :xx)
store_translations(:xx, 'hi' => 'Hello @{!m:Ladies|n:You}')
assert_equal 'Hello Ladies', I18n.t('hi', :gender => :n, :locale => :xx)
assert_equal 'Hello Ladies', I18n.t('hi', :gender => :f, :locale => :xx)
assert_equal 'Hello ', I18n.t('hi', :gender => :m, :locale => :xx)
assert_equal 'Hello Ladies', I18n.t('hi', :locale => :xx)
store_translations(:xx, 'hi' => 'Hello @{!n:Ladies|m,f:You}')
assert_equal 'Hello ', I18n.t('hi', :locale => :xx, :inflector_raises => false)
end
test "backend inflector translate: works with tokens separated by commas and negative tokens" do
store_translations(:xx, 'hi' => 'Dear @{!f,!m:Someone|m:Sir}!')
assert_equal 'Dear Someone!', I18n.t('hi', :gender => :m, :locale => :xx)
assert_equal 'Dear Someone!', I18n.t('hi', :gender => :n, :locale => :xx)
store_translations(:xx, 'hi' => 'Dear @{!f,!m,n:Someone|m:Sir}!')
assert_equal 'Dear Someone!', I18n.t('hi', :gender => :m, :locale => :xx)
assert_equal 'Dear Someone!', I18n.t('hi', :gender => :n, :locale => :xx)
store_translations(:xx, 'hi' => 'Dear @{!f,n:Someone|m:Sir|f:Lady}!')
assert_equal 'Dear Someone!', I18n.t('hi', :gender => :m, :locale => :xx)
assert_equal 'Dear Lady!', I18n.t('hi', :gender => :f, :locale => :xx)
assert_equal 'Dear Someone!', I18n.t('hi', :locale => :xx)
end
test "backend inflector translate: works with aliased patterns" do
store_translations(:xx, 'hi' => 'Dear @{masculine:Sir|feminine:Lady|n:You|All}!')
assert_equal 'Dear Sir!', I18n.t('hi', :gender => :m, :locale => :xx, :inflector_aliased_patterns => true)
assert_equal 'Dear Sir!', I18n.t('hi', :gender => :masculine, :locale => :xx, :inflector_aliased_patterns => true)
assert_equal 'Dear Lady!', I18n.t('hi', :gender => :f, :locale => :xx, :inflector_aliased_patterns => true)
assert_equal 'Dear Lady!', I18n.t('hi', :gender => :feminine, :locale => :xx, :inflector_aliased_patterns => true)
assert_equal 'Dear All!', I18n.t('hi', :gender => :s, :locale => :xx, :inflector_aliased_patterns => true)
assert_equal 'Dear You!', I18n.t('hi', :locale => :xx, :inflector_aliased_patterns => true)
I18n.inflector.options.aliased_patterns = true
assert_equal 'Dear Sir!', I18n.t('hi', :gender => :masculine, :locale => :xx)
end
test "backend inflector translate: works with Method and Proc object given as inflection options" do
def femme
kind, locale = yield
(locale == :xx && kind == :gender) ? :f : :m
end
def excluded
:s
end
def bad_method(a,b,c)
:m
end
procek = method(:femme)
procun = method(:excluded)
badmet = method(:bad_method)
assert_equal 'Dear Lady!', I18n.t('welcome', :gender => procek, :locale => :xx, :inflector_raises => true)
assert_equal 'Dear Lady!', I18n.t('named_welcome', :gender => procek, :locale => :xx, :inflector_raises => true)
assert_equal 'Dear Sir!', I18n.t('named_welcome', :@gender => procek, :locale => :xx, :inflector_raises => true)
assert_equal 'Dear You!', I18n.t('named_welcome', :@gender => procun, :locale => :xx, :inflector_excluded_defaults => true)
assert_equal 'Dear All!', I18n.t('named_welcome', :@gender => procun, :locale => :xx, :inflector_excluded_defaults => false)
assert_raise(ArgumentError) { I18n.t('named_welcome', :@gender => badmet, :locale => :xx, :inflector_raises => true) }
assert_equal 'Dear Sir!', I18n.t('named_welcome', :@gender => lambda{|k,l|:m}, :locale => :xx, :inflector_raises => true)
assert_equal 'Dear Lady!', I18n.t('welcome', :gender => lambda{|k,l| k==:gender ? :f : :s},
:locale => :xx, :inflector_raises => true)
end
test "backend inflector translate: recognizes named patterns and strict kinds" do
store_translations(:xx, :i18n => { :inflections => { :@gender => { :s => 'sir', :o => 'other', :s => 'a', :n => 'n', :default => 'n' }}})
store_translations(:xx, 'hi' => 'Dear @gender{s:Sir|o:Other|n:You|All}!')
assert_equal 'Dear Sir!', I18n.t('hi', :gender => :s, :locale => :xx)
assert_equal 'Dear Other!', I18n.t('hi', :gender => :o, :locale => :xx)
assert_equal 'Dear You!', I18n.t('hi', :locale => :xx)
assert_equal 'Dear You!', I18n.t('hi', :gender => "", :locale => :xx)
assert_equal 'Dear You!', I18n.t('hi', :gender => :unknown, :locale => :xx)
assert_equal 'Dear You!', I18n.t('hi', :@gender => :unknown, :locale => :xx)
end
test "backend inflector translate: prioritizes @-style kinds in options for named patterns" do
store_translations(:xx, :i18n => { :inflections => { :@gender => { :s => 'sir', :o => 'other', :s => 'a', :n => 'n', :default => 'n' }}})
store_translations(:xx, 'hi' => 'Dear @gender{s:Sir|o:Other|n:You|All}!')
assert_equal 'Dear Sir!', I18n.t('hi', :gender => :s, :locale => :xx)
assert_equal 'Dear You!', I18n.t('hi', :gender => :s, :@gender => :unknown, :locale => :xx)
assert_equal 'Dear You!', I18n.t('hi', :gender => :s, :@gender => nil, :locale => :xx)
assert_equal 'Dear Sir!', I18n.t('hi', :gender => :s, :@gender => :s, :locale => :xx)
end
test "backend inflector translate: is immune to reserved or bad content" do
store_translations(:xx, :i18n => { :inflections => { :@gender => { :s => 'sir', :o => 'other', :s => 'a', :n => 'n', :default => 'n' }}})
store_translations(:xx, :i18n => { :inflections => { :@tense => { :now => ''}}})
store_translations(:xx, 'hi' => 'Dear @nonexistant{s:Sir|o:Other|n:You|All}!')
assert_equal 'Dear All!', I18n.t('hi', :gender => 'm', :locale => :xx)
store_translations(:xx, 'hi' => 'Dear @gender{s:Sir|o:Other|n:You|All}!')
assert_equal 'Dear You!', I18n.t('hi', :gender => '@', :@gender => '+', :locale => :xx)
assert_equal 'Dear You!', I18n.t('hi', :gender => '', :@gender => '', :locale => :xx)
store_translations(:xx, 'hi' => '@gender+tense{m+now:~|f+past:she was}')
assert_equal 'male ', I18n.t('hi', :gender => :m, :tense => :now, :locale => :xx)
assert_raise I18n::ArgumentError do
I18n.t('', :gender => :s, :locale => :xx)
end
assert_raise I18n::InvalidInflectionKind do
store_translations(:xx, 'hop' => '@gen,der{m+now:~|f+past:she was}')
I18n.t('hop', :gender => :s, :locale => :xx, :inflector_raises => true)
end
assert_raise I18n::InvalidInflectionToken do
I18n.backend.store_translations(:xx, 'hop' => '@{m+now:~|f+past:she was}')
I18n.t('hop', :gender => :s, :locale => :xx, :inflector_raises => true)
end
assert_raise I18n::InvalidInflectionKind do
store_translations(:xx, 'hi' => 'Dear @uuuuuuuu{s:Sir|o:Other|n:You|All}!')
I18n.t('hi', :gender => 'm', :locale => :xx, :inflector_raises => true)
end
assert_raise I18n::MisplacedInflectionToken do
store_translations(:xx, 'hi' => 'Dear @tense{s:Sir|o:Other|n:You|All}!')
I18n.t('hi', :gender => 'm', :locale => :xx, :inflector_raises => true)
end
I18n.backend = Backend.new
assert_raise I18n::BadInflectionKind do
store_translations(:xx, :i18n => { :inflections => { :@gender => 'something' }})
end
I18n.backend = Backend.new
store_translations(:xx, 'hi' => '@gender+tense{m+now:~|f+past:she was}')
assert_equal '', I18n.t('hi', :gender => :s, :@gender => :s, :locale => :xx)
assert_raise I18n::BadInflectionToken do
store_translations(:xx, :i18n => { :inflections => { :@gender => { :sb => '@', :d=>'1'}}})
end
I18n.backend = Backend.new
assert_raise I18n::BadInflectionToken do
store_translations(:xx, :i18n => { :inflections => { :@gender => { :sa => nil, :d=>'1'}}})
end
I18n.backend = Backend.new
assert_raise I18n::BadInflectionToken do
store_translations(:xx, :i18n => { :inflections => { :@gender => { '' => 'a', :d=>'1'}}})
end
['@',',','cos,cos','@cos+cos','+','cos!cos',':','cos:',':cos','cos:cos','!d'].each do |token|
I18n.backend = Backend.new
assert_raise I18n::BadInflectionToken do
store_translations(:xx, :i18n => { :inflections => { :@gender => { token.to_sym => 'a', :d=>'1' }}})
end
end
['@',',','inflector_something','default','cos,cos','@cos+cos','+','cos!cos',':','cos:',':cos','cos:cos','!d'].each do |kind|
I18n.backend = Backend.new
assert_raise I18n::BadInflectionKind do
store_translations(:xx, :i18n => { :inflections => { kind.to_sym => { :s => 'a', :d=>'1' }}})
end
end
end
test "inflector inflected_locales: lists languages that support inflection" do
assert_equal [:xx], I18n.inflector.inflected_locales
assert_equal [:xx], I18n.inflector.inflected_locales(:gender)
end
test "inflector.strict inflected_locales: lists languages that support inflection" do
assert_equal [:xx], I18n.inflector.strict.inflected_locales
assert_equal [:xx], I18n.inflector.strict.inflected_locales(:gender)
store_translations(:yy, :i18n => { :inflections => { :@person => { :s => 'sir'}}})
assert_equal [:xx], I18n.inflector.strict.inflected_locales(:gender)
assert_equal [:yy], I18n.inflector.strict.inflected_locales(:person)
assert_equal [:xx], I18n.inflector.inflected_locales(:gender)
assert_equal [:yy], I18n.inflector.inflected_locales(:@person)
assert_equal [:xx,:yy], I18n.inflector.inflected_locales.sort{|k,v| k.to_s<=>v.to_s}
assert_equal [:xx,:yy], I18n.inflector.strict.inflected_locales.sort{|k,v| k.to_s<=>v.to_s}
store_translations(:zz, :i18n => { :inflections => { :some => { :s => 'sir'}}})
assert_equal [:xx,:yy,:zz], I18n.inflector.inflected_locales.sort{|k,v| k.to_s<=>v.to_s}
assert_equal [:xx,:yy], I18n.inflector.strict.inflected_locales.sort{|k,v| k.to_s<=>v.to_s}
assert_equal [], I18n.inflector.inflected_locales(:@some)
assert_equal [:zz], I18n.inflector.inflected_locales(:some)
end
test "inflector inflected_locale?: tests if the given locale supports inflection" do
assert_equal true, I18n.inflector.inflected_locale?(:xx)
I18n.locale = :xx
assert_equal true, I18n.inflector.inflected_locale?
end
test "inflector.strict inflected_locale?: tests if the given locale supports inflection" do
assert_equal true, I18n.inflector.strict.inflected_locale?(:xx)
I18n.locale = :xx
assert_equal true, I18n.inflector.strict.inflected_locale?
end
test "inflector new_database creates a database with inflections" do
assert_kind_of I18n::Inflector::InflectionData, I18n.inflector.new_database(:yy)
assert_equal true, I18n.inflector.inflected_locale?(:yy)
assert_equal false, I18n.inflector.inflected_locale?(:yyyyy)
end
test "inflector add_database adds existing database with inflections" do
db = I18n::Inflector::InflectionData.new(:zz)
assert_kind_of I18n::Inflector::InflectionData, I18n.inflector.add_database(db)
assert_equal true, I18n.inflector.inflected_locale?(:zz)
assert_equal false, I18n.inflector.inflected_locale?(:zzzzzz)
end
test "inflector delete_database deletes existing inflections database" do
I18n.inflector.new_database(:vv)
assert_equal true, I18n.inflector.inflected_locale?(:vv)
assert_kind_of NilClass, I18n.inflector.delete_database(:vv)
assert_equal false, I18n.inflector.inflected_locale?(:vv)
end
test "inflector locale_supported?: checks if a language supports inflection" do
assert_equal true, I18n.inflector.locale_supported?(:xx)
assert_equal false, I18n.inflector.locale_supported?(:pl)
assert_equal false, I18n.inflector.locale_supported?(nil)
assert_equal false, I18n.inflector.locale_supported?("")
I18n.locale = :xx
assert_equal true, I18n.inflector.locale_supported?
I18n.locale = :pl
assert_equal false, I18n.inflector.locale_supported?
I18n.locale = nil
assert_equal false, I18n.inflector.locale_supported?
I18n.locale = ""
assert_equal false, I18n.inflector.locale_supported?
end
test "inflector.strict locale_supported?: checks if a language supports inflection" do
assert_equal true, I18n.inflector.strict.locale_supported?(:xx)
assert_equal false, I18n.inflector.strict.locale_supported?(:pl)
assert_equal false, I18n.inflector.strict.locale_supported?(nil)
assert_equal false, I18n.inflector.strict.locale_supported?("")
I18n.locale = :xx
assert_equal true, I18n.inflector.strict.locale_supported?
I18n.locale = :pl
assert_equal false, I18n.inflector.strict.locale_supported?
I18n.locale = nil
assert_equal false, I18n.inflector.strict.locale_supported?
I18n.locale = ""
assert_equal false, I18n.inflector.strict.locale_supported?
end
test "inflector has_token?: checks if a token exists" do
assert_equal true, I18n.inflector.has_token?(:neuter, :gender, :xx)
assert_equal true, I18n.inflector.has_token?(:neuter, :xx)
assert_equal true, I18n.inflector.has_token?(:f, :xx)
assert_equal true, I18n.inflector.has_token?(:you, :xx)
I18n.locale = :xx
assert_equal true, I18n.inflector.has_token?(:f)
assert_equal true, I18n.inflector.has_token?(:you)
assert_equal false,I18n.inflector.has_token?(:faafaffafafa)
end
test "inflector.strict has_token?: checks if a token exists" do
assert_equal true, I18n.inflector.strict.has_token?(:neuter, :gender, :xx)
assert_equal true, I18n.inflector.strict.has_token?(:f, :gender, :xx)
assert_equal false, I18n.inflector.strict.has_token?(:you, :gender)
I18n.locale = :xx
assert_equal true, I18n.inflector.strict.has_token?(:f, :gender)
assert_equal false, I18n.inflector.strict.has_token?(:you, :gender)
assert_equal false, I18n.inflector.strict.has_token?(:faafaffafafa)
end
test "inflector has_kind?: checks if an inflection kind exists" do
assert_equal true, I18n.inflector.has_kind?(:gender, :xx)
assert_equal true, I18n.inflector.has_kind?(:person, :xx)
assert_equal false, I18n.inflector.has_kind?(:nonono, :xx)
assert_equal false, I18n.inflector.has_kind?(nil, :xx)
I18n.locale = :xx
assert_equal true, I18n.inflector.has_kind?(:gender)
assert_equal true, I18n.inflector.has_kind?(:person)
assert_equal false, I18n.inflector.has_kind?(:faafaffafafa)
end
test "inflector.strict has_kind?: checks if an inflection kind exists" do
assert_equal true, I18n.inflector.strict.has_kind?(:gender, :xx)
assert_equal false, I18n.inflector.strict.has_kind?(:person, :xx)
assert_equal false, I18n.inflector.strict.has_kind?(nil, :xx)
I18n.locale = :xx
assert_equal true, I18n.inflector.strict.has_kind?(:gender)
assert_equal false, I18n.inflector.strict.has_kind?(nil)
assert_equal false, I18n.inflector.strict.has_kind?(:faafaffa)
end
test "inflector kind: checks what is the inflection kind of the given token" do
assert_equal :gender, I18n.inflector.kind(:neuter, :xx)
assert_equal :gender, I18n.inflector.kind(:f, :xx)
assert_equal :person, I18n.inflector.kind(:you, :xx)
assert_equal nil, I18n.inflector.kind(nil, :xx)
assert_equal nil, I18n.inflector.kind(nil, nil)
assert_equal nil, I18n.inflector.kind(:nononono,:xx)
I18n.locale = :xx
assert_equal :gender, I18n.inflector.kind(:neuter)
assert_equal :gender, I18n.inflector.kind(:f)
assert_equal :person, I18n.inflector.kind(:you)
assert_equal nil, I18n.inflector.kind(nil)
assert_equal nil, I18n.inflector.kind(:faafaffa)
end
test "inflector.strict kind: checks what is the inflection kind of the given token" do
assert_equal :gender, I18n.inflector.strict.kind(:neuter, :gender, :xx)
assert_equal :gender, I18n.inflector.strict.kind(:f, :gender, :xx)
assert_equal nil, I18n.inflector.strict.kind(:f, :nontrue, :xx)
assert_equal nil, I18n.inflector.strict.kind(:f, nil, :xx)
assert_equal nil, I18n.inflector.strict.kind(nil, :gender, :xx)
assert_equal nil, I18n.inflector.strict.kind(nil, nil, :xx)
assert_equal nil, I18n.inflector.strict.kind(:faafaffafafa, nil, :xx)
assert_equal nil, I18n.inflector.strict.kind(:nil, :faafafa, :xx)
I18n.locale = :xx
assert_equal :gender, I18n.inflector.strict.kind(:neuter, :gender)
assert_equal :gender, I18n.inflector.strict.kind(:f, :gender)
assert_equal nil, I18n.inflector.strict.kind(:f, :nontrue)
assert_equal nil, I18n.inflector.strict.kind(nil, :gender)
assert_equal nil, I18n.inflector.strict.kind(nil, nil)
assert_equal nil, I18n.inflector.strict.kind(:faafaffa)
end
test "inflector true_token: gets true token for the given token name" do
assert_equal :n, I18n.inflector.true_token(:neuter, :xx)
assert_equal :f, I18n.inflector.true_token(:f, :xx)
I18n.locale = :xx
assert_equal :n, I18n.inflector.true_token(:neuter)
assert_equal :f, I18n.inflector.true_token(:f)
assert_equal :f, I18n.inflector.true_token(:f, :xx)
assert_equal nil, I18n.inflector.true_token(:f, :person, :xx)
assert_equal nil, I18n.inflector.true_token(:f, :nokind, :xx)
assert_equal nil, I18n.inflector.true_token(:faafaffa)
end
test "inflector.strict true_token: gets true token for the given token name" do
assert_equal :n, I18n.inflector.strict.true_token(:neuter, :gender, :xx )
assert_equal :f, I18n.inflector.strict.true_token(:f, :gender, :xx )
I18n.locale = :xx
assert_equal :n, I18n.inflector.strict.true_token(:neuter, :gender )
assert_equal :f, I18n.inflector.strict.true_token(:f, :gender )
assert_equal :f, I18n.inflector.strict.true_token(:f, :gender, :xx )
assert_equal nil, I18n.inflector.strict.true_token(:f, :person, :xx )
assert_equal nil, I18n.inflector.strict.true_token(:f, nil, :xx )
assert_equal nil, I18n.inflector.strict.true_token(:faafaffa)
end
test "inflector has_true_token?: tests if true token exists for the given token name" do
assert_equal false, I18n.inflector.has_true_token?(:neuter, :xx )
assert_equal true, I18n.inflector.has_true_token?(:f, :xx )
I18n.locale = :xx
assert_equal false, I18n.inflector.has_true_token?(:neuter )
assert_equal true, I18n.inflector.has_true_token?(:f )
assert_equal true, I18n.inflector.has_true_token?(:f, :xx )
assert_equal false, I18n.inflector.has_true_token?(:f, :person, :xx)
assert_equal false, I18n.inflector.has_true_token?(:f, :nokind, :xx)
assert_equal false, I18n.inflector.has_true_token?(:faafaff)
end
test "inflector strict markers: tests if named markers in kinds are working for API calls" do
tt= {:m=>"male",:f=>"female",:n=>"neuter",:s=>"strange"}
t = tt.merge({:masculine=>"male",:feminine=>"female",:neuter=>"neuter",:neutral=>"neuter"})
al= {:masculine=>:m,:feminine=>:f,:neuter=>:n,:neutral=>:n}
tr= tt.merge(al)
assert_equal [:xx], I18n.inflector.inflected_locales( :@gender )
assert_equal t, I18n.inflector.tokens( :@gender, :xx )
assert_equal tt, I18n.inflector.true_tokens( :@gender, :xx )
assert_equal tr, I18n.inflector.raw_tokens( :@gender, :xx )
assert_equal :n, I18n.inflector.default_token( :@gender, :xx )
assert_equal al, I18n.inflector.aliases( :@gender, :xx )
assert_equal true, I18n.inflector.has_kind?( :@gender, :xx )
assert_equal true, I18n.inflector.has_alias?( :neuter, :@gender, :xx )
assert_equal true, I18n.inflector.has_token?( :n, :@gender, :xx )
assert_equal false, I18n.inflector.has_true_token?( :neuter, :@gender, :xx )
assert_equal true, I18n.inflector.has_true_token?( :n, :@gender, :xx )
assert_equal :n, I18n.inflector.true_token( :neuter, :@gender, :xx )
assert_equal "neuter",I18n.inflector.token_description( :neuter, :@gender, :xx )
assert_equal "neuter",I18n.inflector.token_description( :n, :@gender, :xx )
I18n.locale = :xx
assert_equal t, I18n.inflector.tokens( :@gender )
assert_equal tt, I18n.inflector.true_tokens( :@gender )
assert_equal tr, I18n.inflector.raw_tokens( :@gender )
assert_equal :n, I18n.inflector.default_token( :@gender )
assert_equal al, I18n.inflector.aliases( :@gender )
assert_equal true, I18n.inflector.has_kind?( :@gender )
assert_equal true, I18n.inflector.has_alias?( :neuter, :@gender )
assert_equal true, I18n.inflector.has_token?( :n, :@gender )
assert_equal false, I18n.inflector.has_true_token?( :neuter, :@gender )
assert_equal true, I18n.inflector.has_true_token?( :n, :@gender )
assert_equal :n, I18n.inflector.true_token( :neuter, :@gender )
assert_equal "neuter",I18n.inflector.token_description( :neuter, :@gender )
assert_equal "neuter",I18n.inflector.token_description( :n, :@gender )
end
test "inflector.strict has_true_token?: tests if true token exists for the given token name" do
assert_equal false, I18n.inflector.strict.has_true_token?(:neuter, :gender, :xx )
assert_equal true, I18n.inflector.strict.has_true_token?(:f, :gender, :xx )
I18n.locale = :xx
assert_equal false, I18n.inflector.strict.has_true_token?(:neuter, :gender )
assert_equal true, I18n.inflector.strict.has_true_token?(:f, :gender )
assert_equal true, I18n.inflector.strict.has_true_token?(:f, :gender, :xx )
assert_equal false, I18n.inflector.strict.has_true_token?(:f, :person, :xx )
assert_equal false, I18n.inflector.strict.has_true_token?(:f, nil, :xx )
assert_equal false, I18n.inflector.strict.has_true_token?(:faafaff)
end
test "inflector kinds: lists inflection kinds" do
assert_not_nil I18n.inflector.kinds(:xx)
assert_equal [:gender,:person], I18n.inflector.kinds(:xx).sort{|k,v| k.to_s<=>v.to_s}
I18n.locale = :xx
assert_equal [:gender,:person], I18n.inflector.kinds.sort{|k,v| k.to_s<=>v.to_s}
end
test "inflector.strict kinds: lists inflection kinds" do
assert_not_nil I18n.inflector.strict.kinds(:xx)
assert_equal [:gender], I18n.inflector.strict.kinds(:xx)
I18n.locale = :xx
assert_equal [:gender], I18n.inflector.strict.kinds
end
test "inflector tokens: lists all inflection tokens including aliases" do
h = {:m=>"male",:f=>"female",:n=>"neuter",:s=>"strange",
:masculine=>"male",:feminine=>"female",:neuter=>"neuter",
:neutral=>"neuter"}
ha = h.merge(:i=>'I', :you=>'You')
assert_equal h, I18n.inflector.tokens(:gender, :xx)
I18n.locale = :xx
assert_equal h, I18n.inflector.tokens(:gender)
assert_equal ha, I18n.inflector.tokens
end
test "inflector.strict tokens: lists all inflection tokens including aliases" do
h = {:m=>"male",:f=>"female",:n=>"neuter",:s=>"strange",
:masculine=>"male",:feminine=>"female",:neuter=>"neuter",
:neutral=>"neuter"}
assert_equal h, I18n.inflector.strict.tokens(:gender, :xx)
I18n.locale = :xx
assert_equal h, I18n.inflector.strict.tokens(:gender)
assert_equal Hash.new, I18n.inflector.strict.tokens
end
test "inflector true_tokens: lists true tokens" do
h = {:m=>"male",:f=>"female",:n=>"neuter",:s=>"strange"}
ha = h.merge(:i=>"I",:you=>"You")
assert_equal h, I18n.inflector.true_tokens(:gender, :xx)
I18n.locale = :xx
assert_equal h, I18n.inflector.true_tokens(:gender)
assert_equal ha, I18n.inflector.true_tokens
end
test "inflector.strict true_tokens: lists true tokens" do
h = {:m=>"male",:f=>"female",:n=>"neuter",:s=>"strange"}
assert_equal h, I18n.inflector.strict.true_tokens(:gender, :xx)
I18n.locale = :xx
assert_equal h, I18n.inflector.strict.true_tokens(:gender)
assert_equal Hash.new, I18n.inflector.strict.true_tokens
end
test "inflector raw_tokens: lists tokens in a so called raw format" do
h = {:m=>"male",:f=>"female",:n=>"neuter",:s=>"strange",
:masculine=>:m,:feminine=>:f,:neuter=>:n,
:neutral=>:n}
ha = h.merge(:i=>'I',:you=>"You")
assert_equal h, I18n.inflector.raw_tokens(:gender, :xx)
I18n.locale = :xx
assert_equal h, I18n.inflector.raw_tokens(:gender)
assert_equal ha, I18n.inflector.raw_tokens
end
test "inflector.strict raw_tokens: lists tokens in a so called raw format" do
h = {:m=>"male",:f=>"female",:n=>"neuter",:s=>"strange",
:masculine=>:m,:feminine=>:f,:neuter=>:n,
:neutral=>:n}
assert_equal h, I18n.inflector.strict.raw_tokens(:gender, :xx)
I18n.locale = :xx
assert_equal h, I18n.inflector.strict.raw_tokens(:gender)
assert_equal Hash.new, I18n.inflector.strict.raw_tokens
end
test "inflector default_token: returns a default token for a kind" do
assert_equal :n, I18n.inflector.default_token(:gender, :xx)
I18n.locale = :xx
assert_equal :n, I18n.inflector.default_token(:gender)
end
test "inflector.strict default_token: returns a default token for a kind" do
assert_equal :n, I18n.inflector.strict.default_token(:gender, :xx)
I18n.locale = :xx
assert_equal :n, I18n.inflector.strict.default_token(:gender)
end
test "inflector aliases: lists aliases" do
a = {:masculine=>:m, :feminine=>:f, :neuter=>:n, :neutral=>:n}
assert_equal a, I18n.inflector.aliases(:gender, :xx)
I18n.locale = :xx
assert_equal a, I18n.inflector.aliases(:gender)
assert_equal a, I18n.inflector.aliases
end
test "inflector.strict aliases: lists aliases" do
a = {:masculine=>:m, :feminine=>:f, :neuter=>:n, :neutral=>:n}
assert_equal a, I18n.inflector.strict.aliases(:gender, :xx)
I18n.locale = :xx
assert_equal a, I18n.inflector.strict.aliases(:gender)
assert_equal Hash.new, I18n.inflector.strict.aliases
end
test "inflector token_description: returns token's description" do
assert_equal "male", I18n.inflector.token_description(:m, :xx)
I18n.locale = :xx
assert_equal "male", I18n.inflector.token_description(:m)
assert_equal nil, I18n.inflector.token_description(:vnonexistent, :xx)
assert_equal "neuter", I18n.inflector.token_description(:neutral, :xx)
end
test "inflector.strict token_description: returns token's description" do
assert_equal "male", I18n.inflector.strict.token_description(:m, :gender, :xx)
I18n.locale = :xx
assert_equal "male", I18n.inflector.strict.token_description(:m, :gender)
assert_equal nil, I18n.inflector.strict.token_description(:bnonexistent, :gender, :xx)
assert_equal "neuter", I18n.inflector.strict.token_description(:neutral, :gender, :xx)
end
test "inflector has_alias?: tests whether a token is an alias" do
assert_equal true, I18n.inflector.has_alias?(:neutral, :xx)
assert_equal false, I18n.inflector.has_alias?(:you, :xx)
assert_equal true, I18n.inflector.has_alias?(:neutral, :gender, :xx)
assert_equal false, I18n.inflector.has_alias?(:you, :gender, :xx)
assert_equal false, I18n.inflector.has_alias?(:neutral, :nokind, :xx)
I18n.locale = :xx
assert_equal true, I18n.inflector.has_alias?(:neutral)
end
test "inflector.strict has_alias?: tests whether a token is an alias" do
assert_equal true, I18n.inflector.strict.has_alias?(:neutral, :gender, :xx)
assert_equal false, I18n.inflector.strict.has_alias?(:you, :person, :xx)
assert_equal false, I18n.inflector.strict.has_alias?(:you, :gender, :xx)
I18n.locale = :xx
assert_equal true, I18n.inflector.strict.has_alias?(:neutral, :gender)
end
end
i18n-inflector-2.6.7/test/test_helper.rb 0000644 0000041 0000041 00000001237 13321144047 020144 0 ustar www-data www-data require 'test/unit'
require 'test_declarative'
require 'i18n-inflector'
class Test::Unit::TestCase
def teardown
I18n.locale = nil
I18n.default_locale = :en
I18n.load_path = []
I18n.available_locales = nil
I18n.backend = nil
end if not method_defined?(:teardown)
def translations
I18n.backend.instance_variable_get(:@translations)
end
def store_translations(*args)
data = args.pop
locale = args.pop || :en
I18n.backend.store_translations(locale, data)
end
end
Object.class_eval do
def meta_class
class << self; self; end
end
end unless Object.method_defined?(:meta_class)
i18n-inflector-2.6.7/data.tar.gz.sig 0000644 0000041 0000041 00000000400 13321144047 017132 0 ustar www-data www-data _i+yp'G I1$e@{`1J!z\0i{^iPz4mS!^GXocx0R3KIz ,u!̥ࣘ_t69#/H-iAMfב@jzX{n9}msG5
ϒX-# 習|^ )Iv/u" MO pNC
MJ'W_\ߓ+ i18n-inflector-2.6.7/metadata.gz.sig 0000644 0000041 0000041 00000000400 13321144047 017214 0 ustar www-data www-data .5&2yPȫ6M63k/sGH1-}O.>u3^މ`|Sу9(t?AP1'=? 6i)VJ~()-ydu8+2QaBi?·xO(FI~Du#0pie'< Ds(BGK!=FGT'Ab lKABb'%qwlk6'K{D i18n-inflector-2.6.7/.gemtest 0000644 0000041 0000041 00000000000 13321144047 015756 0 ustar www-data www-data i18n-inflector-2.6.7/Rakefile 0000644 0000041 0000041 00000005473 13321144047 015775 0 ustar www-data www-data # encoding: utf-8
# -*- ruby -*-
$:.unshift File.join(File.dirname(__FILE__), "lib")
require 'rubygems'
require 'bundler/setup'
require "rake"
require "rake/clean"
require "fileutils"
require 'i18n-inflector/version'
require 'hoe'
task :default do
Rake::Task[:test].invoke
Rake::Task[:test].reenable
Rake::Task[:testv4].invoke
end
# Update Gemfile for I18n in version 4
task :gemfilev4 do
gemprev = ENV['BUNDLE_GEMFILE']
ENV['BUNDLE_GEMFILE'] = 'ci/i18nv4-Gemfile'
`rake bundler:gemfile`
ENV['BUNDLE_GEMFILE'] = gemprev
end
# Tests for I18n in version 4
task :testv4 do
gemprev = ENV['BUNDLE_GEMFILE']
ENV['BUNDLE_GEMFILE'] = 'ci/i18nv4-Gemfile'
`bundle install`
Rake::Task[:test].invoke
ENV['BUNDLE_GEMFILE'] = gemprev
end
desc "install by setup.rb"
task :install do
sh "sudo ruby setup.rb install"
end
### Gem
# Issue has been fixed in Psych, see:
# https://github.com/tenderlove/psych/commit/fe65329ce9ece399d61dadf1610e342ff456654e
#
#if !defined?(YAML::ENGINE).nil? && YAML::ENGINE.respond_to?(:yamler)
# YAML::ENGINE.yamler = 'syck'
#end
Hoe.plugin :bundler
Hoe.plugin :yard
Hoe.spec 'i18n-inflector' do
developer I18n::Inflector::DEVELOPER, I18n::Inflector::EMAIL
self.version = I18n::Inflector::VERSION
self.rubyforge_name = I18n::Inflector::NAME
self.summary = I18n::Inflector::SUMMARY
self.description = I18n::Inflector::DESCRIPTION
self.url = I18n::Inflector::URL
self.test_globs = %w(test/**/*_test.rb)
self.remote_rdoc_dir = ''
self.rsync_args << '--chmod=a+rX'
self.readme_file = 'README.rdoc'
self.history_file = 'docs/HISTORY'
extra_deps << ['i18n', '>= 0.4.1']
extra_dev_deps << ['test_declarative', '>= 0.0.5'] <<
['yard', '>= 0.8.6'] <<
['rdoc', '>= 3.8.0'] <<
['bundler', '>= 1.0.15'] <<
['hoe-bundler', '>= 1.2.0']
unless extra_dev_deps.flatten.include?('hoe-yard')
extra_dev_deps << ['hoe-yard', '>= 0.1.2']
end
end
task 'Manifest.txt' do
puts 'generating Manifest.txt from git'
sh %{git ls-files | grep -v gitignore > Manifest.txt}
sh %{git add Manifest.txt}
end
task 'ChangeLog' do
sh %{git log > ChangeLog}
end
desc "Fix documentation's file permissions"
task :docperm do
sh %{chmod -R a+rX doc}
end
### Sign & Publish
desc "Create signed tag in Git"
task :tag do
sh %{git tag -s v#{I18n::Inflector::VERSION} -m 'version #{I18n::Inflector::VERSION}'}
end
desc "Create external GnuPG signature for Gem"
task :gemsign do
sh %{gpg -u #{I18n::Inflector::EMAIL} -ab pkg/#{I18n::Inflector::NAME}-#{I18n::Inflector::VERSION}.gem \
-o pkg/#{I18n::Inflector::NAME}-#{I18n::Inflector::VERSION}.gem.sig}
end
i18n-inflector-2.6.7/lib/ 0000755 0000041 0000041 00000000000 13321144047 015065 5 ustar www-data www-data i18n-inflector-2.6.7/lib/i18n-inflector/ 0000755 0000041 0000041 00000000000 13321144047 017627 5 ustar www-data www-data i18n-inflector-2.6.7/lib/i18n-inflector/version.rb 0000644 0000041 0000041 00000001450 13321144047 021641 0 ustar www-data www-data # encoding: utf-8
#
# Author:: Paweł Wilk (mailto:pw@gnu.org)
# Copyright:: (c) 2011,2012,2013 by Paweł Wilk
# License:: This program is licensed under the terms of {file:docs/LGPL GNU Lesser General Public License} or {file:docs/COPYING Ruby License}.
#
# This file contains version information.
module I18n
module Inflector
# @private
DEVELOPER = 'Paweł Wilk'
# @private
EMAIL = 'pw@gnu.org'
# @private
VERSION = '2.6.7'
# @private
NAME = 'i18n-inflector'
# @private
SUMMARY = 'Inflection module for I18n'
# @private
URL = 'https://rubygems.org/gems/i18n-inflector/'
# @private
DESCRIPTION = 'Enhances simple I18n backend in a way that it inflects translation data using pattern interpolation.'
end
end
i18n-inflector-2.6.7/lib/i18n-inflector/api_strict.rb 0000644 0000041 0000041 00000101647 13321144047 022326 0 ustar www-data www-data # encoding: utf-8
#
# Author:: Paweł Wilk (mailto:pw@gnu.org)
# Copyright:: (c) 2011,2012,2013 by Paweł Wilk
# License:: This program is licensed under the terms of {file:docs/LGPL GNU Lesser General Public License} or {file:docs/COPYING Ruby License}.
#
# This file contains I18n::Inflector::API_Strict class,
# which handles public API for managing inflection data
# for named patterns (strict kinds).
module I18n
module Inflector
# This class contains common operations
# that can be performed on inflection data describing
# strict kinds and tokens assigned to them (used in named
# patterns). It is used by the regular {I18n::Inflector::API API}
# and present there as {I18n::Inflector::API#strict strict}
# instance attribute.
#
# It operates on the database containing instances
# of {I18n::Inflector::InflectionData_Strict} indexed by locale
# names and has methods to access the inflection data in an easy way.
# It can operate on a database and options passed to initializer;
# if they aren't passet it will create them.
#
# ==== Usage
# You can access the instance of this class attached to
# default I18n backend by calling:
# I18n.backend.inflector.strict
# or in a short form:
# I18n.inflector.strict
#
# In most cases using the regular {I18n::Inflector::API} instance
# may be sufficient to operate on inflection data,
# because the regular API (instantiated as I18n.inflector)
# is aware of strict kinds and can pass calls from +API_Strict+
# object if the +kind+ argument given in a method call
# contains the +@+ symbol.
#
# For an instance connected to default I18n backend
# the object containing inflection options is shared
# with the regular API.
#
# @api public
class API_Strict
# Initilizes inflector by connecting to internal databases
# used for storing inflection data and options.
#
# @api public
# @note If any given option is +nil+ then a proper object will be created.
# If it's given, then it will be referenced, not copied.
# @param [Hash,nil] idb the strict inflections databases indexed by locale
# @param [I18n::Inflector::InflectionOptions,nil] options the inflection options
def initialize(idb=nil, options=nil)
@idb = idb.nil? ? {} : idb
@options = options.nil? ? I18n::Inflector::InflectionOptions.new : options
@lazy_locales = LazyHashEnumerator.for(@idb)
@inflected_locales_cache = Hash.new
end
# Creates an empty strict inflections database for the specified locale.
#
# @api public
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @param [Symbol] locale the locale for which the inflections database
# should be created
# @return [I18n::Inflector::InflectionData_Strict] the new object for keeping
# inflection data
def new_database(locale)
locale = prep_locale(locale)
@inflected_locales_cache.clear
@idb[locale] = I18n::Inflector::InflectionData_Strict.new(locale)
end
# Attaches {I18n::Inflector::InflectionData_Strict} instance to the
# current object.
#
# @api public
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @note It doesn't create copy of inflection database, it registers the given object.
# @param [I18n::Inflector::InflectionData_Strict] idb inflection data to add
# @return [I18n::Inflector::InflectionData_Strict] the given +idb+ or +nil+ if something
# went wrong (e.g. +nil+ was given as an argument)
def add_database(db)
return nil if db.nil?
locale = prep_locale(db.locale)
delete_database(locale)
@inflected_locales_cache.clear
@idb[locale] = db
end
# Deletes a strict inflections database for the specified locale.
#
# @api public
# @note It detaches the database from {I18n::Inflector::API_Strict} instance.
# Other objects referring to it directly may still use it.
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @param [Symbol] locale the locale for which the inflections database is to be deleted.
# @return [void]
def delete_database(locale)
locale = prep_locale(locale)
return nil if @idb[locale].nil?
@inflected_locales_cache.clear
@idb[locale] = nil
end
# Checks if the given locale was configured to support strict inflection.
#
# @api public
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @return [Boolean] +true+ if a locale supports inflection
# @overload inflected_locale?
# Checks if the current locale was configured to support inflection.
# @return [Boolean] +true+ if the current locale supports inflection
# @overload inflected_locale?(locale)
# Checks if the given locale was configured to support inflection.
# @param [Symbol] locale the locale to test
# @return [Boolean] +true+ if the given locale supports inflection
def inflected_locale?(locale=nil)
not @idb[prep_locale(locale)].nil? rescue false
end
alias_method :locale?, :inflected_locale?
alias_method :locale_supported?, :inflected_locale?
# Iterates through locales which have configured strict inflection support.
#
# @api public
# @return [LazyArrayEnumerator] the lazy enumerator
# @yield [locale] optional block in which each kind will be yielded
# @yieldparam [Symbol] locale the inflected locale identifier
# @yieldreturn [LazyArrayEnumerator] the lazy enumerator
# @overload each_inflected_locale
# Iterates through locales which have configured inflection support.
# @return [LazyArrayEnumerator] the lazy enumerator
# @overload each_inflected_locale(kind)
# Iterates through locales which have configured inflection support for the given +kind+.
# @param [Symbol] kind the identifier of a kind
# @return [LazyArrayEnumerator] the lazy enumerator
def each_inflected_locale(kind=nil, &block)
kind = kind.to_s.empty? ? nil : kind.to_sym
i = @lazy_locales.reject { |lang,data| data.empty? }
i = i.select { |lang,data| data.has_kind?(kind) } unless kind.nil?
i.each_key(&block)
end
alias_method :each_locale, :each_inflected_locale
alias_method :each_supported_locale, :each_inflected_locale
# Gets locales which have configured strict inflection support.
#
# @api public
# @return [Array] the array containing locales that support inflection
# @overload inflected_locales
# Gets locales which have configured inflection support.
# @return [Array] the array containing locales that support inflection
# @overload inflected_locales(kind)
# Gets locales which have configured inflection support for the given +kind+.
# @param [Symbol] kind the identifier of a kind
# @return [Array] the array containing locales that support inflection
def inflected_locales(kind=nil)
kind = kind.to_s.empty? ? nil : kind.to_sym
r = ( @inflected_locales_cache[kind] ||= each_inflected_locale(kind).to_a )
r.nil? ? r : r.dup
end
alias_method :locales, :inflected_locales
alias_method :supported_locales, :inflected_locales
# Iterates through known strict inflection kinds.
#
# @api public
# @return [LazyArrayEnumerator] the lazy enumerator
# @yield [kind] optional block in which each kind will be yielded
# @yieldparam [Symbol] kind the inflection kind
# @yieldreturn [LazyArrayEnumerator] the lazy enumerator
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @overload kinds
# Iterates through known inflection kinds for the current locale.
# @return [LazyArrayEnumerator] the lazy enumerator
# @overload kinds(locale)
# Iterates through known inflection kinds for the given +locale+.
# @param [Symbol] locale the locale for which kinds should be listed
# @return [LazyArrayEnumerator] the lazy enumerator
def each_kind(locale=nil, &block)
data_safe(locale).each_kind(&block)
end
alias_method :each_inflection_kind, :each_kind
# Gets known strict inflection kinds.
#
# @api public
# @return [Array] the array containing known inflection kinds
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @overload kinds
# Gets known inflection kinds for the current locale.
# @return [Array] the array containing known inflection kinds
# @overload kinds(locale)
# Gets known inflection kinds for the given +locale+.
# @param [Symbol] locale the locale for which kinds should be listed
# @return [Array] the array containing known inflection kinds
def kinds(locale=nil)
each_kind(locale).to_a
end
alias_method :inflection_kinds, :kinds
# Tests if a strict kind exists.
#
# @api public
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @return [Boolean] +true+ if the given +kind+ exists, +false+ otherwise
# @overload has_kind?(kind)
# Tests if a strict kind exists for the current locale.
# @param [Symbol] kind the identifier of a kind
# @return [Boolean] +true+ if the given +kind+ exists, +false+ otherwise
# @overload has_kind?(kind, locale)
# Tests if a strict kind exists for the given +locale+.
# @param [Symbol,String] kind the identifier of a kind
# @param [Symbol] locale the locale identifier
# @return [Boolean] +true+ if the given +kind+ exists, +false+ otherwise
def has_kind?(kind, locale=nil)
return false if (kind.nil? || kind.to_s.empty?)
data_safe(locale).has_kind?(kind.to_sym)
end
# Reads default token of the given strict +kind+.
#
# @api public
# @return [Symbol,nil] the default token or +nil+
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @overload default_token(kind)
# This method reads default token of the given +kind+ and the current locale.
# @param [Symbol,String] kind the kind of tokens
# @return [Symbol,nil] the default token or +nil+ if
# there is no default token
# @overload default_token(kind, locale)
# This method reads default token of the given +kind+ and the given +locale+.
# @param [Symbol,String] kind the kind of tokens
# @param [Symbol] locale the locale to use
# @return [Symbol,nil] the default token or +nil+ if
# there is no default token
def default_token(kind, locale=nil)
return nil if (kind.nil? || kind.to_s.empty?)
data_safe(locale).get_default_token(kind.to_sym)
end
# Checks if the given +token+ belonging to a strict kind is an alias.
#
# @api public
# @return [Boolean] +true+ if the given +token+ is an alias, +false+ otherwise
# @raise [I18n::InvalidLocale] if the given +locale+ is invalid
# @raise [ArgumentError] if the count of arguments is invalid
# @overload has_alias?(token, kind)
# Uses the current locale and the given +kind+ to check if the given +token+ is an alias.
# @param [Symbol,String] token name of the checked token
# @param [Symbol,String] kind the kind of the given token
# @return [Boolean] +true+ if the given +token+ is an alias, +false+ otherwise
# @overload has_alias?(token, kind, locale)
# Uses the given +locale+ and +kind+ to check if the given +token+ is an alias.
# @param [Symbol,String] token name of the checked token
# @param [Symbol,String] kind the kind of the given token
# @param [Symbol] locale the locale to use
# @return [Boolean] +true+ if the given +token+ is an alias, +false+ otherwise
def has_alias?(*args)
token, kind, locale = tkl_args(args)
return false if (token.nil? || kind.nil?)
data_safe(locale).has_alias?(token, kind)
end
alias_method :token_is_alias?, :has_alias?
# Checks if the given +token+ belonging to a strict kind is a true token (not alias).
#
# @api public
# @return [Boolean] +true+ if the given +token+ is a true token, +false+ otherwise
# @raise [I18n::InvalidLocale] if the given +locale+ is invalid
# @raise [ArgumentError] if the count of arguments is invalid
# @overload has_true_token?(token, kind)
# Uses the current locale and the given +kind+ to check if the given +token+ is a true token.
# @param [Symbol,String] token name of the checked token
# @param [Symbol,String] kind the kind of the given token
# @return [Boolean] +true+ if the given +token+ is a true token, +false+ otherwise
# @overload has_true_token?(token, kind, locale)
# Uses the given +locale+ and +kind+ to check if the given +token+ is a true token.
# @param [Symbol,String] token name of the checked token
# @param [Symbol,String] kind the kind of the given token
# @param [Symbol] locale the locale to use
# @return [Boolean] +true+ if the given +token+ is a true token, +false+ otherwise
def has_true_token?(*args)
token, kind, locale = tkl_args(args)
return false if (token.nil? || kind.nil?)
data_safe(locale).has_true_token?(token, kind)
end
alias_method :token_is_true?, :has_true_token?
# Checks if the given +token+ belonging to a strict kind exists. It may be an alias or a true token.
#
# @api public
# @return [Boolean] +true+ if the given +token+ exists, +false+ otherwise
# @raise [I18n::InvalidLocale] if the given +locale+ is invalid
# @raise [ArgumentError] if the count of arguments is invalid
# @overload has_token?(token, kind)
# Uses the current locale and the given kind +kind+ to check if the given +token+ exists.
# @param [Symbol,String] token name of the checked token
# @param [Symbol,String] kind the kind of the given token
# @return [Boolean] +true+ if the given +token+ exists, +false+ otherwise
# @overload has_token?(token, kind, locale)
# Uses the given +locale+ and +kind+ to check if the given +token+ exists.
# @param [Symbol,String] token name of the checked token
# @param [Symbol,String] kind the kind of the given token
# @param [Symbol] locale the locale to use
# @return [Boolean] +true+ if the given +token+ exists, +false+ otherwise
def has_token?(*args)
token, kind, locale = tkl_args(args)
return false if (token.nil? || kind.nil?)
data_safe(locale).has_token?(token, kind)
end
alias_method :token_exists?, :has_token?
# Gets true token for the given +token+ belonging to
# a strict kind. If the token is an alias it will be resolved
# and a true token (target) will be returned.
#
# @api public
# @return [Symbol,nil] the true token or +nil+
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @overload true_token(token, kind)
# Uses the current +locale+ and the given +kind+ to get a real token
# for the given +token+. If the token is an alias it will be resolved
# and a true token (target) will be returned.
# @param [Symbol,String] token the identifier of the checked token
# @param [Symbol,String] kind the identifier of a kind
# @return [Symbol,nil] the true token or +nil+
# @overload true_token(token, kind, locale)
# Uses the given +locale+ and +kind+ to get a real token
# for the given +token+. If the token is an alias it will be resolved
# and a true token (target) will be returned.
# @param [Symbol,String] token the identifier of the checked token
# @param [Symbol,String] kind the identifier of a kind
# @param [Symbol] locale the locale to use
# @return [Symbol,nil] the true token or +nil+
def true_token(*args)
token, kind, locale = tkl_args(args)
return nil if (token.nil? || kind.nil?)
data_safe(locale).get_true_token(token, kind)
end
alias_method :resolve_alias, :true_token
# Gets a kind of the given +token+ (which may be an alias) belonging to a strict kind.
#
# @api public
# @return [Symbol,nil] the kind of the given +token+ or +nil+
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @overload kind(token, kind)
# Uses current locale and the given +kind+ to get a kind of
# the given +token+ (which may be an alias).
# @param [Symbol,String] token name of the token or alias
# @param [Symbol,String] kind the identifier of a kind (expectations filter)
# @return [Symbol,nil] the kind of the given +token+ or +nil+
# @overload kind(token, kind, locale)
# Uses the given +locale+ to get a kind of the given +token+ (which may be an alias).
# @param [Symbol,String] token name of the token or alias
# @param [Symbol,String] kind the identifier of a kind (expectations filter)
# @param [Symbol] locale the locale to use
# @return [Symbol,nil] the kind of the given +token+ or +nil+
def kind(token, kind=nil, locale=nil)
return nil if (token.nil? || kind.nil? || token.to_s.empty? || kind.to_s.empty?)
data_safe(locale).get_kind(token.to_sym, kind.to_sym)
end
# Iterates through available inflection tokens belonging to a strict kind and their descriptions.
#
# @api public
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @return [LazyHashEnumerator] the lazy enumerator (token => description)
# @yield [token, description] optional block in which each token will be yielded
# @yieldparam [Symbol] token a token
# @yieldparam [String] description a description string for a token
# @yieldreturn [LazyHashEnumerator] the lazy enumerator
# @note You cannot deduce where aliases are pointing to, since the information
# about a target is replaced by the description. To get targets use the
# {#raw_tokens} method. To simply list aliases and their targets use
# the {#aliases} method.
# @overload each_token(kind)
# Iterates through available inflection tokens and their descriptions for some +kind+ and
# the current locale.
# @param [Symbol,String] kind the kind of inflection tokens to be returned
# @return [LazyHashEnumerator] the lazy enumerator (token => description)
# @overload each_token(kind, locale)
# Iterates through available inflection tokens and their descriptions of the given
# +kind+ and +locale+.
# @param [Symbol,String] kind the kind of inflection tokens to be returned
# @param [Symbol] locale the locale to use
# @return [LazyHashEnumerator] the lazy enumerator (token => description)
def each_token(kind=nil, locale=nil, &block)
kind = kind.to_s.empty? ? nil : kind.to_sym
data_safe(locale).each_token(kind, &block)
end
# Gets available inflection tokens belonging to a strict kind and their descriptions.
#
# @api public
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @return [Hash] the hash containing available inflection tokens and descriptions
# @note You cannot deduce where aliases are pointing to, since the information
# about a target is replaced by the description. To get targets use the
# {#raw_tokens} method. To simply list aliases and their targets use
# the {#aliases} method.
# @overload tokens(kind)
# Gets available inflection tokens and their descriptions for some +kind+ and
# the current locale.
# @param [Symbol,String] kind the kind of inflection tokens to be returned
# @return [Hash] the hash containing available inflection tokens (including
# aliases) as keys and their descriptions as values
# @overload tokens(kind, locale)
# Gets available inflection tokens and their descriptions of the given
# +kind+ and +locale+.
# @param [Symbol,String] kind the kind of inflection tokens to be returned
# @param [Symbol] locale the locale to use
# @return [Hash] the hash containing available inflection tokens (including
# aliases) as keys and their descriptions as values
def tokens(kind=nil, locale=nil)
each_token(kind, locale).to_h
end
# Iterates through available inflection tokens belonging to a strict kind and their values.
#
# @api public
# @return [LazyHashEnumerator] the lazy enumerator (token => description|target)
# @yield [token, value] optional block in which each token will be yielded
# @yieldparam [Symbol] token a token
# @yieldparam [Symbol, String] value a description string for a token or a target (if alias)
# @yieldreturn [LazyHashEnumerator] the lazy enumerator
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @note You may deduce whether the returned values are aliases or true tokens
# by testing if a value is a kind of Symbol or a String.
# @overload each_token_raw(kind)
# Iterates through available inflection tokens and their values of the given +kind+ and
# the current locale.
# @param [Symbol,String] kind the kind of inflection tokens to be returned
# @return [LazyHashEnumerator] the lazy enumerator (token => description|target)
# @overload each_token_raw(kind, locale)
# Iterates through available inflection tokens (and their values) of the given +kind+ and +locale+.
# @param [Symbol,String] kind the kind of inflection tokens to be returned
# @param [Symbol] locale the locale to use
# @return [LazyHashEnumerator] the lazy enumerator (token => description|target)
def each_token_raw(kind=nil, locale=nil, &block)
kind = kind.to_s.empty? ? nil : kind.to_sym
data_safe(locale).each_raw_token(kind, &block)
end
alias_method :each_raw_token, :each_token_raw
# Gets available inflection tokens belonging to a strict kind and their values.
#
# @api public
# @return [Hash] the hash containing available inflection tokens and descriptions (or alias pointers)
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @note You may deduce whether the returned values are aliases or true tokens
# by testing if a value is a kind of Symbol or a String.
# @overload tokens_raw(kind)
# Gets available inflection tokens and their values of the given +kind+ and
# the current locale.
# @param [Symbol,String] kind the kind of inflection tokens to be returned
# @return [Hash] the hash containing available inflection tokens as keys
# and their descriptions as values; in case of aliases the returned
# values are Symbols
# @overload tokens_raw(kind, locale)
# Gets available inflection tokens (and their values) of the given +kind+ and +locale+.
# @param [Symbol,String] kind the kind of inflection tokens to be returned
# @param [Symbol] locale the locale to use
# @return [Hash] the hash containing available inflection tokens as keys
# and their descriptions as values. In case of aliases the returned
# values are Symbols
def tokens_raw(kind=nil, locale=nil)
each_token_raw(kind, locale).to_h
end
alias_method :raw_tokens, :tokens_raw
# Iterates through inflection tokens belonging to a strict kind and their values.
#
# @api public
# @return [LazyHashEnumerator] the lazy enumerator (token => description)
# @yield [token, description] optional block in which each token will be yielded
# @yieldparam [Symbol] token a token
# @yieldparam [String] description a description string for a token
# @yieldreturn [LazyHashEnumerator] the lazy enumerator
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @note It returns only true tokens, not aliases.
# @overload each_token_true(kind)
# Iterates through true inflection tokens (and their values) of the given +kind+ and
# the current locale.
# @param [Symbol,String] kind the kind of inflection tokens to be returned
# @return [LazyHashEnumerator] the lazy enumerator (token => description)
# @overload each_token_true(kind, locale)
# Iterates through true inflection tokens (and their values) of the given +kind+ and +locale+.
# @param [Symbol,String] kind the kind of inflection tokens to be returned
# @param [Symbol] locale the locale to use
# @return [LazyHashEnumerator] the lazy enumerator (token => description)
def each_token_true(kind=nil, locale=nil, &block)
kind = kind.to_s.empty? ? nil : kind.to_sym
data_safe(locale).each_true_token(kind, &block)
end
alias_method :each_true_token, :each_token_true
# Gets true inflection tokens belonging to a strict kind and their values.
#
# @api public
# @return [Hash] the hash containing available inflection tokens and descriptions
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @note It returns only true tokens, not aliases.
# @overload tokens_true(kind)
# Gets true inflection tokens (and their values) of the given +kind+ and
# the current locale.
# @param [Symbol,String] kind the kind of inflection tokens to be returned
# @return [Hash] the hash containing available inflection tokens as keys
# and their descriptions as values
# @overload tokens_true(kind, locale)
# Gets true inflection tokens (and their values) of the given +kind+ and +locale+.
# @param [Symbol,String] kind the kind of inflection tokens to be returned
# @param [Symbol] locale the locale to use
# @return [Hash] the hash containing available inflection tokens as keys
# and their descriptions as values
def tokens_true(kind=nil, locale=nil)
each_token_true(kind, locale).to_h
end
alias_method :true_tokens, :tokens_true
# Iterates through inflection aliases belonging to a strict kind and their pointers.
#
# @api public
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @return [LazyHashEnumerator] the lazy enumerator (token => target)
# @yield [alias, target] optional block in which each alias will be yielded
# @yieldparam [Symbol] alias an alias
# @yieldparam [Symbol] target a name of the target token
# @yieldreturn [LazyHashEnumerator] the lazy enumerator
# @overload each_alias(kind)
# Iterates through inflection aliases (and their pointers) of the given +kind+ and the current locale.
# @param [Symbol,String] kind the kind of aliases to get
# @return [LazyHashEnumerator] the lazy enumerator (token => target)
# @overload each_alias(kind, locale)
# Iterates through inflection aliases (and their pointers) of the given +kind+ and +locale+.
# @param [Symbol,String] kind the kind of aliases to get
# @param [Symbol] locale the locale to use
# @return [LazyHashEnumerator] the lazy enumerator (token => target)
def each_alias(kind=nil, locale=nil, &block)
kind = kind.to_s.empty? ? nil : kind.to_sym
data_safe(locale).each_alias(kind, &block)
end
# Gets inflection aliases belonging to a strict kind and their pointers.
#
# @api public
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @return [Hash] the Hash containing available inflection aliases (alias => target)
# @overload aliases(kind)
# Gets inflection aliases (and their pointers) of the given +kind+ and the current locale.
# @param [Symbol,String] kind the kind of aliases to get
# @return [Hash] the Hash containing available inflection aliases
# @overload aliases(kind, locale)
# Gets inflection aliases (and their pointers) of the given +kind+ and +locale+.
# @param [Symbol,String] kind the kind of aliases to get
# @param [Symbol] locale the locale to use
# @return [Hash] the Hash containing available inflection aliases
def aliases(kind=nil, locale=nil)
each_alias(kind, locale).to_h
end
# Gets the description of the given inflection token belonging to a strict kind.
#
# @api public
# @note If the given +token+ is really an alias it
# returns the description of the true token that
# it points to.
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @return [String,nil] the descriptive string or +nil+
# @overload token_description(token, kind)
# Uses the current locale and the given +token+ to get a description of that token.
# @param [Symbol,String] token the token
# @param [Symbol,String] kind the identifier of a kind
# @return [String,nil] the descriptive string or +nil+ if something
# went wrong (e.g. token was not found)
# @overload token_description(token, kind, locale)
# Uses the given +locale+ and the given +token+ to get a description of that token.
# @param [Symbol,String] token the token
# @param [Symbol,String] kind the identifier of a kind
# @param [Symbol] locale the locale to use
# @return [String,nil] the descriptive string or +nil+ if something
# went wrong (e.g. token was not found)
def token_description(*args)
token, kind, locale = tkl_args(args)
return nil if (token.nil? || kind.nil?)
data_safe(locale).get_description(token, kind)
end
protected
# @private
def data(locale=nil)
@idb[prep_locale(locale)]
end
# @private
def data_safe(locale=nil)
@idb[prep_locale(locale)] || I18n::Inflector::InflectionData_Strict.new(locale)
end
# This method is the internal helper that prepares arguments
# containing +token+, +kind+ and +locale+.
#
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @raise [ArgumentError] if the count of arguments is invalid
# @return [Array] the array containing
# cleaned and validated +token+, +kind+ and +locale+
# @overload tkl_args(token, kind, locale)
# Prepares arguments containing +token+, +kind+ and +locale+.
# @param [String,Hash] token the token
# @param [String,Hash] kind the inflection kind
# @param [String,Hash] locale the locale identifier
# @return [Array] the array containing
# cleaned and validated +token+, +kind+ and +locale+
# @overload tkl_args(token, kind)
# Prepares arguments containing +token+ and +locale+.
# @param [String,Hash] token the token
# @param [String,Hash] kind the inflection kind
# @return [Array] the array containing
# cleaned and validated +token+, +kind+ and +locale+
# @overload tkl_args(token)
# Prepares arguments containing +token+.
# @param [String,Hash] token the token
# @return [Array] the array containing
# cleaned and validated +token+ and the current locale
def tkl_args(args)
token, kind, locale = case args.count
when 1 then [args[0], nil, nil]
when 2 then [args[0], args[1], nil]
when 3 then args
else raise I18n::ArgumentError.new("wrong number of arguments: #{args.count} for (1..3)")
end
token = token.nil? || token.to_s.empty? ? nil : token.to_sym
kind = kind.nil? || kind.to_s.empty? ? nil : kind.to_sym
[token,kind,locale]
end
# Processes +locale+ identifier and validates
# whether it's correct (not empty and not +nil+).
#
# @note If the +locale+ is not correct, it
# tries to use locale from {I18n.locale} and validates it
# as well.
# @param [Symbol,String] locale the locale identifier
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @return [Symbol] the given locale or the global locale
def prep_locale(locale=nil)
locale ||= I18n.locale
raise I18n::InvalidLocale.new(locale) if locale.to_s.empty?
locale.to_sym
end
end # class API_Strict
end # module Inflector
end # module I18n
i18n-inflector-2.6.7/lib/i18n-inflector/errors.rb 0000644 0000041 0000041 00000016127 13321144047 021477 0 ustar www-data www-data # encoding: utf-8
#
# Author:: Paweł Wilk (mailto:pw@gnu.org)
# Copyright:: (c) 2011,2012,2013 by Paweł Wilk
# License:: This program is licensed under the terms of {file:docs/LGPL GNU Lesser General Public License} or {file:docs/COPYING Ruby License}.
#
# This file contains error reporting classes for I18n::Backend::Inflector module.
module I18n
# @abstract It is a parent class for all exceptions
# related to inflections.
class InflectionException < I18n::ArgumentError
attr_accessor :token
attr_accessor :kind
attr_accessor :key
def initialize(locale, token, kind)
@locale, @token, @kind = locale, token, kind
@key = nil
super()
end
end
# @abstract It is a parent class for all exceptions
# related to inflection patterns that are processed.
class InflectionPatternException < InflectionException
attr_accessor :pattern
def initialize(locale, pattern, token, kind)
super(locale, token, kind)
@pattern = pattern
end
def message
mkey = @key.nil? ? "" : ".#{@key}"
@pattern.nil? ? "" : "#{@locale}#{mkey}: #{@pattern} - "
end
end
# @abstract It is a parent class for all exceptions
# related to configuration data of inflections that is processed.
class InflectionConfigurationException < InflectionException
attr_accessor :locale
def message
mkey = @key.nil? ? ".i18n.inflections.#{@kind}" : ".#{@key}"
"#{@locale}#{mkey}: "
end
end
# @abstract It is a parent class for exceptions raised when
# inflection option is bad or missing.
class InvalidOptionForKind < InflectionPatternException
attr_accessor :option
def initialize(locale, pattern, token, kind, option)
super(locale, pattern, token, kind)
@option = option
end
end
# This is raised when there is no kind given in options. The kind
# is determined by looking at token placed in a pattern.
class InflectionOptionNotFound < InvalidOptionForKind
def message
kind = @kind.to_s
unless kind.empty?
if kind[0..0] == I18n::Inflector::Config::Markers::STRICT_KIND
kindmsg = ":#{kind} (or :#{kind[1..-1]})"
else
kindmsg = kind.to_sym.inspect
end
end
"" << super <<
"required option #{kindmsg} was not found"
end
end
# This exception will be raised when a required option, describing token selected
# for a kind contains a token that is not of the given kind.
class InflectionOptionIncorrect < InvalidOptionForKind
def message
"" << super <<
"required value #{@option.inspect} of option #{@kind.inspect} " \
"does not match any token"
end
end
# This is raised when a token given in a pattern is invalid (empty or has no
# kind assigned).
class InvalidInflectionToken < InflectionPatternException
def initialize(locale, pattern, token, kind=nil)
super(locale, pattern, token, kind)
end
def message
badkind = ""
if (!@token.to_s.empty? && !kind.nil?)
kind = @kind.to_s.empty? ? "" : @kind.to_sym
badkind = " (processed kind: #{kind.inspect})"
end
"" << super << "token #{@token.to_s.inspect} is invalid" + badkind
end
end
# This is raised when an inflection option name is invalid (contains
# reserved symbols).
class InvalidInflectionOption < InflectionPatternException
def initialize(locale, pattern, option)
super(locale, pattern, nil, option)
end
def message
"" << super << "inflection option #{@kind.inspect} is invalid"
end
end
# This is raised when a kind given in a pattern is invalid (empty, reserved
# or containing a reserved character).
class InvalidInflectionKind < InflectionPatternException
def initialize(locale, pattern, kind)
super(locale, pattern, nil, kind)
end
def message
"" << super << "kind #{@kind.to_s.inspect} is invalid"
end
end
# This is raised when an inflection token used in a pattern does not match
# an assumed kind determined by reading previous tokens from that pattern
# or by the given strict kind of a named pattern.
class MisplacedInflectionToken < InflectionPatternException
def initialize(locale, pattern, token, kind)
super(locale, pattern, token, kind)
end
def message
"" << super <<
"token #{@token.to_s.inspect} " \
"is not of the expected kind #{@kind.inspect}"
end
end
# This is raised when a complex inflection pattern is malformed
# and cannot be reduced to set of regular patterns.
class ComplexPatternMalformed < InflectionPatternException
def initialize(locale, pattern, token, complex_kind)
unless pattern.include?(I18n::Inflector::Config::Markers::PATTERN)
pattern = I18n::Inflector::Config::Markers::PATTERN + "#{complex_kind}{#{pattern}}"
end
super(locale, pattern, token, complex_kind)
end
def message
"" << super << "pattern is malformed; token count differs from kind count"
end
end
# This is raised when an inflection token of the same name is already defined in
# inflections tree of translation data.
class DuplicatedInflectionToken < InflectionConfigurationException
attr_accessor :original_kind
def initialize(locale, token, kind, original_kind)
super(locale, token, kind)
@original_kind = original_kind
end
def message
"" << super <<
"token #{@token.inspect} " \
"was already assigned to the kind #{@original_kind.inspect}"
end
end
# This is raised when an alias for an inflection token points to a token that
# doesn't exists. It is also raised when default token of some kind points
# to a non-existent token.
class BadInflectionAlias < InflectionConfigurationException
attr_accessor :pointer
def initialize(locale, token, kind, pointer)
super(locale, token, kind)
@pointer = pointer
end
def message
what = token == :default ? "default token" : "alias #{@token.inspect}"
"" << super <<
"the #{what} " \
"points to an unknown token #{@pointer.inspect}"
end
end
# This is raised when an inflection token or its description has a bad name. This
# includes an empty name or a name containing prohibited characters.
class BadInflectionToken < InflectionConfigurationException
attr_accessor :description
def initialize(locale, token, kind=nil, description=nil)
super(locale, token, kind)
@description = description
end
def message
if @description.nil?
"" << super <<
"inflection token #{@token.inspect} " \
"has a bad name"
else
"" << super <<
"inflection token #{@token.inspect} " \
"has a bad description #{@description.inspect}"
end
end
end
# This is raised when an inflection kind has a bad name
# or is not a root for a tree of tokens.
class BadInflectionKind < InflectionConfigurationException
def initialize(locale, kind)
super(locale, nil, kind)
end
def message
"" << super <<
"inflection kind #{@kind.inspect} has bad name or type"
end
end
end
i18n-inflector-2.6.7/lib/i18n-inflector/inflection_data_strict.rb 0000644 0000041 0000041 00000027475 13321144047 024706 0 ustar www-data www-data # encoding: utf-8
#
# Author:: Paweł Wilk (mailto:pw@gnu.org)
# Copyright:: (c) 2011,2012,2013 by Paweł Wilk
# License:: This program is licensed under the terms of {file:docs/LGPL GNU Lesser General Public License} or {file:docs/COPYING Ruby License}.
#
# This file contains class that is used to keep
# inflection data for strict kinds.
# @abstract This namespace is shared with I18n subsystem.
module I18n
module Inflector
# This class contains structures for keeping parsed translation data
# and basic operations for strict kinds and tokens assigned to them.
# Methods in this class vary from methods from {I18n::Inflector::InflectionData}
# in a way that +kind+ argument is usually required, not optional, since
# managing the strict kinds requires a kind of any token to be always known.
class InflectionData_Strict
# This constant contains a dummy hash for an empty token. It makes
# chaining calls to internal data easier.
DUMMY_TOKEN = {:kind=>nil, :target=>nil, :description=>nil}.freeze
# This constant contains a dummy hash of hashes for tokens collection.
# It makes chaining calls to internal data easier.
DUMMY_TOKENS = Hash.new(DUMMY_TOKEN).freeze
# This constant contains a dummy hash. It makes
# chaining calls to internal data easier.
DUMMY_HASH = Hash.new.freeze
# Locale this database works for.
attr_reader :locale
# Initializes internal structures.
#
# @param [Symbol,nil] locale the locale identifier for
# the object to be labeled with
def initialize(locale=nil)
@tokens = Hash.new(DUMMY_TOKENS)
@lazy_kinds = LazyArrayEnumerator.for(@tokens)
@defaults = Hash.new
@locale = locale
end
# Adds an alias (overwriting existing alias).
#
# @param [Symbol] name the name of an alias
# @param [Symbol] target the target token for the created alias
# @param [Symbol] kind the identifier of a kind
# @return [Boolean] +true+ if everything went ok, +false+ otherwise
# (in case of bad names or non-existent targets)
def add_alias(name, target, kind)
return false if (name.nil? || target.nil? || kind.nil?)
return false if (name.to_s.empty? || target.to_s.empty? || kind.to_s.empty?)
name = name.to_sym
target = target.to_sym
kind = kind.to_sym
k = @tokens[kind]
return false unless k.has_key?(target)
token = k[name] = {}
token[:description] = k[target][:description]
token[:target] = target
true
end
# Adds a token (overwriting existing token).
#
# @param [Symbol] token the name of a token to add
# @param [Symbol] kind the identifier of a kind
# @param [String] description the description of a token
# @return [Boolean] +true+ if everything went ok, +false+ otherwise
# (in case of bad names)
def add_token(token, kind, description)
return false if (token.to_s.empty? || kind.to_s.empty? || description.nil?)
token = token.to_sym
kind = kind.to_sym
kind_tree = @tokens[kind]
if kind_tree.equal?(DUMMY_TOKENS)
kind_tree = @tokens[kind] = Hash.new(DUMMY_TOKEN)
end
token = kind_tree[token] = {}
token[:description] = description.to_s
true
end
# Sets the default token for the given strict kind.
#
# @param [Symbol] kind the kind to which the default
# token should be assigned
# @param [Symbol] target the token to set
# @return [void]
def set_default_token(kind, target)
@defaults[kind.to_sym] = target.to_sym
end
# Tests if the given token of the given
# strict kind is a true token.
#
# @param [Symbol] token the identifier of a token
# @param [Symbol] kind the identifier of a kind
# @return [Boolean] +true+ if the given +token+ is
# a token and not an alias, and is a kind of
# the given kind, +false+ otherwise
def has_true_token?(token, kind)
@tokens[kind].has_key?(token) && @tokens[kind][token][:target].nil?
end
# Tests if the given token (or alias) of the
# given strict kind is present.
#
# @param [Symbol] token the identifier of a token
# @param [Symbol] kind the identifier of a kind
# @return [Boolean] +true+ if the given +token+
# (which may be an alias) exists and if kind of
# the given kind
def has_token?(token, kind)
@tokens[kind].has_key?(token)
end
# Tests if a strict kind exists.
#
# @param [Symbol] kind the identifier of a kind
# @return [Boolean] +true+ if the given +kind+ exists
def has_kind?(kind)
@tokens.has_key?(kind)
end
# Tests if the given strict kind has a default
# token assigned.
#
# @param [Symbol] kind the identifier of a kind
# @return [Boolean] +true+ if there is a default
# token of the given kind
def has_default_token?(kind)
@defaults.has_key?(kind)
end
# Tests if the given alias of the given strict
# kind is really an alias.
#
# @param [Symbol] alias_name the identifier of an alias
# @param [Symbol] kind the identifier of a kind
# @return [Boolean] +true+ if the given alias is really an alias
# being a kind of the given kind, +false+ otherwise
def has_alias?(alias_name, kind)
not @tokens[kind][alias_name][:target].nil?
end
# Iterates through all the true tokens (not aliases) of the
# given strict kind.
#
# @param [Symbol] kind the identifier of a kind
# @return [LazyHashEnumerator] the lazy enumerator (token => description)
# @yield [token, description] optional block in which each token will be yielded
# @yieldparam [Symbol] token a token
# @yieldparam [String] description a description string for a token
# @yieldreturn [LazyHashEnumerator] the lazy enumerator
def each_true_token(kind, &block)
LazyHashEnumerator.for(@tokens[kind]).
select { |token,data| data[:target].nil? }.
map { |token,data| data[:description] }.
each(&block)
end
# Iterates through all the aliases of the given strict kind.
#
# @param [Symbol] kind the identifier of a kind
# @return [LazyHashEnumerator] the lazy enumerator (token => target)
# @yield [alias, target] optional block in which each alias will be yielded
# @yieldparam [Symbol] alias an alias
# @yieldparam [Symbol] target a name of the target token
# @yieldreturn [LazyHashEnumerator] the lazy enumerator
def each_alias(kind, &block)
LazyHashEnumerator.for(@tokens[kind]).
reject { |token,data| data[:target].nil? }.
map { |token,data| data[:target] }.
each(&block)
end
# Iterates through all the tokens of the given strict kind
# in a way that it is possible to
# distinguish true tokens from aliases.
#
# @note True tokens have descriptions (String) and aliases
# have targets (Symbol) assigned.
# @param [Symbol] kind the identifier of a kind
# @return [LazyHashEnumerator] the lazy enumerator (token => description|target)
# @yield [token, value] optional block in which each token will be yielded
# @yieldparam [Symbol] token a token
# @yieldparam [Symbol, String] value a description string for a token or a target (if alias)
# @yieldreturn [LazyHashEnumerator] the lazy enumerator
def each_raw_token(kind, &block)
LazyHashEnumerator.for(@tokens[kind]).
map { |token,data| data[:target] || data[:description] }.
each(&block)
end
# Iterates through all the tokens (including aliases) of the given
# strict kind.
#
# @note Use {#each_raw_token} if you want to distinguish
# true tokens from aliases.
# @param [Symbol] kind the identifier of a kind
# @return [LazyHashEnumerator] the lazy enumerator (token => description)
# @yield [token, description] optional block in which each token will be yielded
# @yieldparam [Symbol] token a token
# @yieldparam [String] description a description string for a token
# @yieldreturn [LazyHashEnumerator] the lazy enumerator
def each_token(kind, &block)
LazyHashEnumerator.for(@tokens[kind]).
map{ |token,data| data[:description] }.
each(&block)
end
# Gets a target token for the given alias of a strict kind.
#
# @param [Symbol] alias_name the identifier of an alias
# @param [Symbol] kind the identifier of a kind
# @return [Symbol,nil] the token that the given alias points to
# or +nil+ if it isn't really an alias
def get_target_for_alias(alias_name, kind)
@tokens[kind][alias_name][:target]
end
# Gets a strict kind of the given token or alias.
#
# @note This method may be concidered dummy since there is a
# need to give the inflection kind, but it's here in order
# to preserve compatibility with the same method from
# {I18n::Inflector::InflectionData} which guesses the kind.
# @param [Symbol] token identifier of a token
# @param [Symbol] kind the identifier of a kind (expectations filter)
# @return [Symbol,nil] the kind of the given +token+
# or +nil+ if the token is unknown or is not of the given kind
def get_kind(token, kind)
@tokens[kind].has_key?(token) ? kind : nil
end
# Gets a true token (of the given strict kind) for the given
# identifier.
#
# @note If the given +token+ is really an alias it will
# be resolved and the real token pointed by that alias
# will be returned.
# @param [Symbol] token the identifier of a token
# @param [Symbol] kind the identifier of a kind
# @return [Symbol,nil] the true token for the given +token+
# or +nil+ if the token is unknown or is not a kind of the
# given +kind+
def get_true_token(token, kind)
o = @tokens[kind]
return nil unless o.has_key?(token)
o = o[token]
o[:target].nil? ? token : o[:target]
end
# Iterates through all known strict kinds.
#
# @return [LazyArrayEnumerator] the lazy enumerator
# @yield [kind] optional block in which each kind will be yielded
# @yieldparam [Symbol] kind the inflection kind
# @yieldreturn [LazyArrayEnumerator] the lazy enumerator
def each_kind(&block)
@lazy_kinds.map{|k,v| k}.each(&block)
end
# Reads the default token of a strict kind.
#
# @note It will always return true token (not an alias).
# @param [Symbol] kind the identifier of a kind
# @return [Symbol,nil] the default token of the given +kind+
# or +nil+ if there is no default token set
def get_default_token(kind)
@defaults[kind]
end
# Gets a description of a token or alias belonging to a strict kind.
#
# @note If the token is really an alias it will resolve the alias first.
# @param [Symbol] token the identifier of a token
# @param [Symbol] kind the identifier of a kind
# @return [String,nil] the string containing description of the given
# token (which may be an alias) or +nil+ if the token is unknown
def get_description(token, kind)
@tokens[kind][token][:description]
end
# Test if the inflection data have no elements.
#
# @return [Boolean] +true+ if the inflection data
# have no elements
def empty?
@tokens.empty?
end
end # InflectionData_Strict
end
end
i18n-inflector-2.6.7/lib/i18n-inflector/api.rb 0000644 0000041 0000041 00000114476 13321144047 020742 0 ustar www-data www-data # encoding: utf-8
#
# Author:: Paweł Wilk (mailto:pw@gnu.org)
# Copyright:: (c) 2011,2012,2013 by Paweł Wilk
# License:: This program is licensed under the terms of {file:docs/LGPL GNU Lesser General Public License} or {file:docs/COPYING Ruby License}.
#
# This file contains {I18n::Inflector::API} class,
# which is public API for I18n Inflector.
module I18n
module Inflector
# Instance of this class, the inflector, is attached
# to I18n backend. This class contains common operations
# that can be performed on inflections. It can operate
# on both unnamed an named patterns (regular and strict kinds).
# This class is used by backend methods to interpolate
# strings and load inflections.
#
# It uses the databases containing instances of
# {I18n::Inflector::InflectionData} and {I18n::Inflector::InflectionData_Strict}
# that are stored in the Hashes and indexed by locale names.
#
# Note that strict kinds used to handle named patterns
# internally are stored in a different database than
# regular kinds. Most of the methods of this class are also
# aware of strict kinds and will call proper methods handling
# strict inflection data when the +@+ symbol is detected
# at the beginning of the given identifier of a kind.
#
# ==== Usage
# You can access the instance of this class attached to
# default I18n backend by calling:
# I18n.backend.inflector
# or in a short form:
# I18n.inflector
# In case of named patterns (strict kinds):
# I18n.inflector.strict
#
# @see I18n::Inflector::API_Strict The API_Strict class
# for accessing inflection data for named
# patterns (strict kinds).
# @see file:docs/EXAMPLES The examples of real-life usage.
# @api public
class API < API_Strict
include I18n::Inflector::Interpolate
# Options controlling the engine.
#
# @api public
# @return [I18n::Inflector::InflectionOptions] the set of options
# controlling inflection engine
# @see I18n::Inflector::InflectionOptions#raises
# @see I18n::Inflector::InflectionOptions#unknown_defaults
# @see I18n::Inflector::InflectionOptions#excluded_defaults
# @see I18n::Inflector::InflectionOptions#aliased_patterns
# @example Usage of +options+:
# # globally set raises flag
# I18n.inflector.options.raises = true
#
# # globally set raises flag (the same meaning as the example above)
# I18n.backend.inflector.options.raises = true
#
# # set raises flag just for this translation
# I18n.translate('welcome', :inflector_raises => true)
attr_reader :options
# @private
def config
I18n::Inflector::Config
end
# @private
def strict
@strict ||= I18n::Inflector::API_Strict.new(@idb_strict, @options)
end
# Initilizes the inflector by creating internal databases
# used for storing inflection data and options.
#
# @api public
def initialize
super(nil, nil)
@idb_strict = {}
end
# Creates a database for the specified locale.
#
# @api public
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @param [Symbol] locale the locale for which the inflections database is to be created
# @return [I18n::Inflector::InflectionData] the new object for keeping inflection data
def new_database(locale)
locale = prep_locale(locale)
@idb[locale] = I18n::Inflector::InflectionData.new(locale)
end
# Creates internal databases (regular and strict) for the specified locale.
#
# @api public
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @param [Symbol] locale the locale for which the inflections databases are to be created
# @return [Array] the
# array of objects for keeping inflection data
def new_databases(locale)
normal = new_databases(locale)
strict = strict.new_database(locale)
[normal, strict]
end
# Attaches instance of {I18n::Inflector::InflectionData} and
# optionally {I18n::Inflector::InflectionData_Strict}
# to the inflector.
#
# @api public
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @note It doesn't create a copy of inflection data, but registers the given object(s).
# @return [I18n::Inflector::InflectionData,Array,nil]
# @overload add_database(db)
# @param [I18n::Inflector::InflectionData] db inflection data to add
# @return [I18n::Inflector::InflectionData,nil] the given object or +nil+
# if something went wrong (e.g. +nil+ was given as an argument)
# @overload add_database(db, db_strict)
# @note An array is returned and databases are
# used only if both databases are successfully attached. References to
# both databases will be unset if there would be a problem with attaching
# any of them.
# @param [I18n::Inflector::InflectionData] db inflection data to add
# @param [I18n::Inflector::InflectionData_Strict] db_strict strict inflection data to add
# @return [Array,nil] the
# array of the given objects or +nil+ if something went wrong (e.g. +nil+ was
# given as the first argument)
def add_database(db, db_strict=nil)
r = super(db)
return r if (r.nil? || db_strict.nil?)
r_strict = strict.add_database(db_strict)
if r_strict.nil?
delete_database(db.locale)
return nil
end
[r, r_strict]
end
alias_method :add_databases, :add_database
# Deletes the internal databases for the specified locale.
#
# @api public
# @note It detaches the databases from {I18n::Inflector::API} instance.
# Other objects referring to them may still use it.
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @param [Symbol] locale the locale for which the inflections database is to be deleted.
# @return [void]
def delete_databases(locale)
delete_database(locale)
strict.delete_database(locale)
end
# Checks if the given locale was configured to support inflection.
#
# @api public
# @note That method uses information from regular and strict kinds.
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @return [Boolean] +true+ if a locale supports inflection
# @overload inflected_locale?(locale)
# Checks if the given locale was configured to support inflection.
# @param [Symbol] locale the locale to test
# @return [Boolean] +true+ if the given locale supports inflection
# @overload inflected_locale?
# Checks if the current locale was configured to support inflection.
# @return [Boolean] +true+ if the current locale supports inflection
def inflected_locale?(locale=nil)
super || strict.inflected_locale?(locale)
end
alias_method :locale?, :inflected_locale?
alias_method :locale_supported?, :inflected_locale?
# Gets locales which have configured inflection support.
#
# @api public
# @note This method uses information from both regular and strict kinds.
# @return [Array] the array containing locales that support inflection
#
# @overload inflected_locales
# Gets locales which have configured inflection support.
# @return [Array] the array containing locales that support inflection
# @overload inflected_locales(kind)
# Gets locales which have configured inflection support for the given +kind+.
# @param [Symbol] kind the identifier of a kind
# @return [Array] the array containing locales that support inflection
# @note If +kind+ begins with the +@+ symbol then the variant of this method
# operating on strict kinds will be called ({I18n::Inflector::API_Strict#inflected_locales})
def inflected_locales(kind=nil)
if kind.to_s[0..0] == Markers::STRICT_KIND
strict.inflected_locales(kind.to_s[1..-1])
else
kind = kind.to_s.empty? ? nil : kind.to_sym
r = ( @inflected_locales_cache[kind] ||= super(kind).uniq )
r.nil? ? r : r.dup
end
end
# Iterates through locales which have configured inflection support.
#
# @api public
# @note This method uses information from both regular and strict kinds.
# The locale identifiers may be duplicated!
# @return [LazyArrayEnumerator] the lazy enumerator
# @yield [locale] optional block in which each kind will be yielded
# @yieldparam [Symbol] locale the inflected locale identifier
# @yieldreturn [LazyArrayEnumerator] the lazy enumerator
# @overload each_inflected_locale
# Iterates through locales which have configured inflection support.
# @return [LazyArrayEnumerator] the lazy enumerator
# @overload each_inflected_locale(kind)
# Iterates through locales which have configured inflection support for the given +kind+.
# @param [Symbol] kind the identifier of a kind
# @return [LazyArrayEnumerator] the lazy enumerator
def each_inflected_locale(kind=nil, &block)
super + strict.inflected_locales(kind)
end
alias_method :each_locale, :each_inflected_locale
alias_method :each_supported_locale, :each_inflected_locale
# Tests if a kind exists.
#
# @api public
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @return [Boolean] +true+ if the given +kind+ exists, +false+ otherwise
# @note If +kind+ begins with the +@+ symbol then the variant of this method
# operating on strict kinds will be called ({I18n::Inflector::API_Strict#has_kind?})
# @overload has_kind?(kind)
# Tests if a regular kind exists for the current locale.
# @param [Symbol] kind the identifier of a kind
# @return [Boolean] +true+ if the given +kind+ exists for the current
# locale, +false+ otherwise
# @overload has_kind?(kind, locale)
# Tests if a regular kind exists for the given +locale+.
# @param [Symbol,String] kind the identifier of a kind
# @param [Symbol] locale the locale identifier
# @return [Boolean] +true+ if the given +kind+ exists, +false+ otherwise
def has_kind?(kind, locale=nil)
if kind.to_s[0..0] == Markers::STRICT_KIND
return strict.has_kind?(kind.to_s[1..-1], locale)
end
super
end
# Reads default token for the given +kind+.
#
# @api public
# @return [Symbol,nil] the default token or +nil+
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @note If +kind+ begins with the +@+ symbol then the variant of this method
# operating on strict kinds will be called ({I18n::Inflector::API_Strict#default_token})
# @overload default_token(kind)
# This method reads default token for the given +kind+ and the current locale.
# @param [Symbol,String] kind the kind of tokens
# @return [Symbol,nil] the default token or +nil+ if
# there is no default token
# @overload default_token(kind, locale)
# This method reads default token for the given +kind+ and the given +locale+.
# @param [Symbol,String] kind the kind of tokens
# @param [Symbol] locale the locale to use
# @return [Symbol,nil] the default token or +nil+ if
# there is no default token
def default_token(kind, locale=nil)
return nil if (kind.nil? || kind.to_s.empty?)
if kind.to_s[0..0] == Markers::STRICT_KIND
return strict.default_token(kind.to_s[1..-1], locale)
end
super
end
# Checks if the given +token+ is an alias.
#
# @api public
# @note By default it uses regular kinds database, not strict kinds.
# @return [Boolean] +true+ if the given +token+ is an alias, +false+ otherwise
# @raise [I18n::InvalidLocale] if the given +locale+ is invalid
# @raise [ArgumentError] if the count of arguments is invalid
# @overload has_alias?(token)
# Uses current locale to check if the given +token+ is an alias.
# @param [Symbol,String] token name of the checked token
# @return [Boolean] +true+ if the given +token+ is an alias, +false+ otherwise
# @overload has_alias?(token, locale)
# Uses the given +locale+ to check if the given +token+ is an alias.
# @param [Symbol,String] token name of the checked token
# @param [Symbol] locale the locale to use
# @return [Boolean] +true+ if the given +token+ is an alias, +false+ otherwise
# @overload has_alias?(token, kind, locale)
# Uses the given +locale+ and +kind+ to check if the given +token+ is an alias.
# @note If +kind+ begins with the +@+ symbol then the variant of this method
# operating on strict kinds will be called ({I18n::Inflector::API_Strict#has_alias?})
# @param [Symbol,String] token name of the checked token
# @param [Symbol,String] kind the kind used to narrow the check
# @param [Symbol] locale the locale to use
# @return [Boolean] +true+ if the given +token+ is an alias, +false+ otherwise
# @overload has_alias?(token, strict_kind)
# Uses the current locale and the given +strict_kind+ (which name must begin with
# the +@+ symbol) to check if the given +token+ is an alias.
# @note It calls {I18n::Inflector::API_Strict#has_alias?} on strict kinds data.
# @param [Symbol,String] token name of the checked token
# @param [Symbol,String] strict_kind the kind of the given alias
# @return [Boolean] +true+ if the given +token+ is an alias, +false+ otherwise
def has_alias?(*args)
token, kind, locale = tkl_args(args)
return false if (token.nil? || token.to_s.empty?)
unless kind.nil?
kind = kind.to_s
reutrn false if kind.empty?
if kind[0..0] == Markers::STRICT_KIND
return strict.has_alias?(token, kind[1..-1], locale)
end
kind = kind.to_sym
end
data_safe(locale).has_alias?(token.to_sym, kind)
end
alias_method :token_has_alias?, :has_alias?
# Checks if the given +token+ is a true token (not alias).
#
# @api public
# @note By default it uses regular kinds database, not strict kinds.
# @return [Boolean] +true+ if the given +token+ is a true token, +false+ otherwise
# @raise [I18n::InvalidLocale] if the given +locale+ is invalid
# @raise [ArgumentError] if the count of arguments is invalid
# @overload has_true_token?(token)
# Uses current locale to check if the given +token+ is a true token.
# @param [Symbol,String] token name of the checked token
# @return [Boolean] +true+ if the given +token+ is a true token, +false+ otherwise
# @overload has_true_token?(token, locale)
# Uses the given +locale+ to check if the given +token+ is a true token.
# @param [Symbol,String] token name of the checked token
# @param [Symbol] locale the locale to use
# @return [Boolean] +true+ if the given +token+ is a true token, +false+ otherwise
# @overload has_true_token?(token, kind, locale)
# Uses the given +locale+ and +kind+ to check if the given +token+ is a true token.
# @note If +kind+ begins with the +@+ symbol then the variant of this method
# operating on strict kinds will be called ({I18n::Inflector::API_Strict#has_true_token?})
# @param [Symbol,String] token name of the checked token
# @param [Symbol,String] kind the kind used to narrow the check
# @param [Symbol] locale the locale to use
# @return [Boolean] +true+ if the given +token+ is a true token, +false+ otherwise
# @overload has_true_token?(token, strict_kind)
# Uses the current locale and the given +strict_kind+ (which name must begin with
# the +@+ symbol) to check if the given +token+ is a true token.
# @note It calls {I18n::Inflector::API_Strict#has_true_token?} on strict kinds data.
# @param [Symbol,String] token name of the checked token
# @param [Symbol,String] strict_kind the kind of the given token
# @return [Boolean] +true+ if the given +token+ is a true token, +false+ otherwise
def has_true_token?(*args)
token, kind, locale = tkl_args(args)
return false if (token.nil? || token.to_s.empty?)
unless kind.nil?
kind = kind.to_s
return false if kind.empty?
if kind[0..0] == Markers::STRICT_KIND
return strict.has_true_token?(token, kind[1..-1], locale)
end
kind = kind.to_sym
end
data_safe(locale).has_true_token?(token.to_sym, kind)
end
alias_method :token_has_true?, :has_true_token?
# Checks if the given +token+ exists. It may be an alias or a true token.
#
# @api public
# @note By default it uses regular kinds database, not strict kinds.
# @return [Boolean] +true+ if the given +token+ exists, +false+ otherwise
# @raise [I18n::InvalidLocale] if the given +locale+ is invalid
# @raise [ArgumentError] if the count of arguments is invalid
# @overload has_token?(token)
# Uses current locale to check if the given +token+ is a token.
# @param [Symbol,String] token name of the checked token
# @return [Boolean] +true+ if the given +token+ exists, +false+ otherwise
# @overload has_token?(token, locale)
# Uses the given +locale+ to check if the given +token+ exists.
# @param [Symbol,String] token name of the checked token
# @param [Symbol] locale the locale to use
# @return [Boolean] +true+ if the given +token+ exists, +false+ otherwise
# @overload has_token?(token, kind, locale)
# Uses the given +locale+ and +kind+ to check if the given +token+ exists.
# @note If +kind+ begins with the +@+ symbol then the variant of this method
# operating on strict kinds will be called ({I18n::Inflector::API_Strict#has_token?})
# @param [Symbol,String] token name of the checked token
# @param [Symbol,String] kind the kind used to narrow the check
# @param [Symbol] locale the locale to use
# @return [Boolean] +true+ if the given +token+ exists, +false+ otherwise
# @overload has_token?(token, strict_kind)
# Uses the current locale and the given +strict_kind+ (which name must begin with
# the +@+ symbol) to check if the given +token+ exists.
# @note It calls {I18n::Inflector::API_Strict#has_token?} on strict kinds data.
# @param [Symbol,String] token name of the checked token
# @param [Symbol,String] strict_kind the kind of the given token
# @return [Boolean] +true+ if the given +token+ exists, +false+ otherwise
def has_token?(*args)
token, kind, locale = tkl_args(args)
return false if (token.nil? || token.to_s.empty?)
unless kind.nil?
kind = kind.to_s
return false if kind.empty?
if kind[0..0] == Markers::STRICT_KIND
return strict.has_token?(token, kind[1..-1], locale)
end
kind = kind.to_sym
end
data_safe(locale).has_token?(token.to_sym, kind)
end
alias_method :token_exists?, :has_token?
# Gets true token for the given +token+. If the token
# is an alias it will be resolved
# and a true token (target) will be returned.
# @note By default it uses regular kinds database, not strict kinds.
# @api public
# @return [Symbol,nil] the true token or +nil+
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @overload true_token(token)
# Uses current locale to get a real token for the given +token+.
# @param [Symbol,String] token name of the checked token
# @return [Symbol,nil] the true token or +nil+
# @overload true_token(token, locale)
# Uses the given +locale+ to get a real token for the given +token+.
# If the token is an alias it will be resolved
# and a true token (target) will be returned.
# @param [Symbol,String] token name of the checked token
# @param [Symbol] locale the locale to use
# @return [Symbol,nil] the true token or +nil+
# @overload true_token(token, kind, locale)
# Uses the given +locale+ and +kind+ to get a real token for the given +token+.
# If the token is an alias it will be resolved
# and a true token (target) will be returned.
# @note If +kind+ begins with the +@+ symbol then the variant of this method
# operating on strict kinds will be called ({I18n::Inflector::API_Strict#true_token})
# @param [Symbol,String] token name of the checked token
# @param [Symbol,String] kind the kind of the given token
# @param [Symbol] locale the locale to use
# @return [Symbol,nil] the true token or +nil+
# @overload true_token(token, strict_kind)
# Uses the current locale and the given +strict_kind+ (which name must begin with
# the +@+ symbol) to get a real token for the given +token+.
# @note It calls {I18n::Inflector::API_Strict#true_token} on strict kinds data.
# @param [Symbol,String] token name of the checked token
# @param [Symbol,String] strict_kind the kind of the given token
# @return [Symbol,nil] the true token
def true_token(*args)
token, kind, locale = tkl_args(args)
return nil if (token.nil? || token.to_s.empty?)
unless kind.nil?
kind = kind.to_s
return nil if kind.empty?
if kind[0..0] == Markers::STRICT_KIND
return strict.true_token(token, kind[1..-1], locale)
end
kind = kind.to_sym
end
data_safe(locale).get_true_token(token.to_sym, kind)
end
alias_method :resolve_alias, :true_token
# Gets a kind for the given +token+ (which may be an alias).
#
# @api public
# @note By default it uses regular kinds database, not strict kinds.
# @return [Symbol,nil] the kind of the given +token+ or +nil+
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @overload kind(token)
# Uses the current locale to get a kind of the given +token+ (which may be an alias).
# @param [Symbol,String] token name of the token or alias
# @return [Symbol,nil] the kind of the given +token+
# @overload kind(token, locale)
# Uses the given +locale+ to get a kind of the given +token+ (which may be an alias).
# @param [Symbol,String] token name of the token or alias
# @param [Symbol] locale the locale to use
# @return [Symbol,nil] the kind of the given +token+
# @overload kind(token, kind, locale)
# Uses the given +locale+ to get a kind of the given +token+ (which may be an alias).
# @note If +kind+ begins with the +@+ symbol then the variant of this method
# operating on strict kinds will be called ({I18n::Inflector::API_Strict#kind})
# @param [Symbol,String] token name of the token or alias
# @param [Symbol,String] kind the kind name to narrow the search
# @param [Symbol] locale the locale to use
# @return [Symbol,nil] the kind of the given +token+
# @overload kind(token, strict_kind)
# Uses the current locale and the given +strict_kind+ (which name must begin with
# the +@+ symbol) to get a kind of the given +token+ (which may be an alias).
# @note It calls {I18n::Inflector::API_Strict#kind} on strict kinds data.
# @param [Symbol,String] token name of the token or alias
# @param [Symbol,String] kind the kind of the given token
# @return [Symbol,nil] the kind of the given +token+
def kind(*args)
token, kind, locale = tkl_args(args)
return nil if (token.nil? || token.to_s.empty?)
unless kind.nil?
kind = kind.to_s
return nil if kind.empty?
if kind[0..0] == Markers::STRICT_KIND
return strict.kind(token, kind[1..-1], locale)
end
kind = kind.to_sym
end
data_safe(locale).get_kind(token.to_sym, kind)
end
# Iterates through available inflection tokens and their descriptions.
#
# @api public
# @note By default it uses regular kinds database, not strict kinds.
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @return [LazyHashEnumerator] the lazy enumerator (token => description)
# @yield [token, description] optional block in which each token will be yielded
# @yieldparam [Symbol] token a token
# @yieldparam [String] description a description string for a token
# @yieldreturn [LazyHashEnumerator] the lazy enumerator
# @note You cannot deduce where aliases are pointing to, since the information
# about a target is replaced by the description. To get targets use the
# {#raw_tokens} method. To simply list aliases and their targets use
# the {#aliases} method.
# @overload each_token
# Iterates through available inflection tokens and their descriptions.
# @return [LazyHashEnumerator] the lazy enumerator (token => description)
# @overload each_token(kind)
# Iterates through available inflection tokens and their descriptions for some +kind+.
# @note If +kind+ begins with the +@+ symbol then the variant of this method
# operating on strict kinds will be called ({I18n::Inflector::API_Strict#each_token})
# @param [Symbol,String] kind the kind of inflection tokens to be returned
# @return [LazyHashEnumerator] the lazy enumerator (token => description)
# @overload each_token(kind, locale)
# Iterates through available inflection tokens and their descriptions for some +kind+ and +locale+.
# @note If +kind+ begins with the +@+ symbol then the variant of this method
# operating on strict kinds will be called ({I18n::Inflector::API_Strict#each_token})
# @param [Symbol,String] kind the kind of inflection tokens to be returned
# @param [Symbol] locale the locale to use
# @return [LazyHashEnumerator] the lazy enumerator (token => description)
def each_token(kind=nil, locale=nil)
if kind.to_s[0..0] == Markers::STRICT_KIND
return strict.each_token(kind.to_s[1..-1], locale)
end
super
end
# Iterates through available inflection tokens and their values.
#
# @api public
# @return [LazyHashEnumerator] the lazy enumerator (token => description|target)
# @yield [token, value] optional block in which each token will be yielded
# @yieldparam [Symbol] token a token
# @yieldparam [Symbol, String] value a description string for a token or a target (if alias)
# @yieldreturn [LazyHashEnumerator] the lazy enumerator
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @note You may deduce whether the returned values are aliases or true tokens
# by testing if a value is a type of Symbol or String.
# @overload each_token_raw
# Iterates through available inflection tokens and their values for regular kinds.
# @return [LazyHashEnumerator] the lazy enumerator (token => description|target)
# @overload each_token_raw(kind)
# Iterates through available inflection tokens and their values for the given +kind+.
# @note If +kind+ begins with the +@+ symbol then the variant of this method
# operating on strict kinds will be called ({I18n::Inflector::API_Strict#each_token_raw})
# @param [Symbol,String] kind the kind of inflection tokens to be returned
# @return [LazyHashEnumerator] the lazy enumerator (token => description|target)
# @overload each_token_raw(kind, locale)
# Iterates through available inflection tokens and their values for the given +kind+ and +locale+.
# @note If +kind+ begins with the +@+ symbol then the variant of this method
# operating on strict kinds will be called ({I18n::Inflector::API_Strict#each_token_raw})
# @param [Symbol,String] kind the kind of inflection tokens to be returned
# @param [Symbol] locale the locale to use
# @return [LazyHashEnumerator] the lazy enumerator (token => description|target)
def each_token_raw(kind=nil, locale=nil)
if kind.to_s[0..0] == Markers::STRICT_KIND
return strict.each_token_raw(kind.to_s[1..-1], locale)
end
super
end
alias_method :each_raw_token, :each_token_raw
# Iterates through true inflection tokens and their values.
#
# @api public
# @return [LazyHashEnumerator] the lazy enumerator (token => description)
# @yield [token, description] optional block in which each token will be yielded
# @yieldparam [Symbol] token a token
# @yieldparam [String] description a description string for a token
# @yieldreturn [LazyHashEnumerator] the lazy enumerator
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @note It returns only true tokens, not aliases.
# @overload each_token_true
# Iterates through true inflection tokens and their values for regular kinds.
# @return [LazyHashEnumerator] the lazy enumerator (token => description)
# @overload each_token_true(kind)
# Iterates through true inflection tokens and their values for the given +kind+.
# @note If +kind+ begins with the +@+ symbol then the variant of this method
# operating on strict kinds will be called ({I18n::Inflector::API_Strict#each_token_true})
# @param [Symbol,String] kind the kind of inflection tokens to be returned
# @return [LazyHashEnumerator] the lazy enumerator (token => description)
# @overload each_token_true(kind, locale)
# Iterates through true inflection tokens and their values for the given +kind+ and +value+.
# @note If +kind+ begins with the +@+ symbol then the variant of this method
# operating on strict kinds will be called ({I18n::Inflector::API_Strict#each_token_true})
# @param [Symbol,String] kind the kind of inflection tokens to be returned
# @param [Symbol] locale the locale to use
# @return [LazyHashEnumerator] the lazy enumerator (token => description)
def each_token_true(kind=nil, locale=nil, &block)
if kind.to_s[0..0] == Markers::STRICT_KIND
return strict.each_token_true(kind.to_s[1..-1], locale, &block)
end
super
end
alias_method :each_true_token, :each_token_true
# Iterates through inflection aliases and their pointers.
#
# @api public
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @return [LazyHashEnumerator] the lazy enumerator (token => target)
# @yield [alias, target] optional block in which each alias will be yielded
# @yieldparam [Symbol] alias an alias
# @yieldparam [Symbol] target a name of the target token
# @yieldreturn [LazyHashEnumerator] the lazy enumerator
# @overload each_alias(kind)
# Iterates through inflection aliases (and their pointers) of the given +kind+ and the current locale.
# @note If +kind+ begins with the +@+ symbol then the variant of this method
# operating on strict kinds will be called ({I18n::Inflector::API_Strict#each_alias})
# @param [Symbol,String] kind the kind of aliases to get
# @return [LazyHashEnumerator] the lazy enumerator (token => target)
# @overload each_alias(kind, locale)
# Iterates through inflection aliases (and their pointers) of the given +kind+ and +locale+.
# @note If +kind+ begins with the +@+ symbol then the variant of this method
# operating on strict kinds will be called ({I18n::Inflector::API_Strict#each_alias})
# @param [Symbol,String] kind the kind of aliases to get
# @param [Symbol] locale the locale to use
# @return [LazyHashEnumerator] the lazy enumerator (token => target)
def each_alias(kind=nil, locale=nil, &block)
if kind.to_s[0..0] == Markers::STRICT_KIND
return strict.each_alias(kind.to_s[1..-1], locale, &block)
end
super
end
# Gets the description of the given inflection token.
#
# @api public
# @note If the given +token+ is really an alias it
# returns the description of the true token that
# it points to. By default it uses regular kinds database,
# not strict kinds.
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @return [String,nil] the descriptive string or +nil+
# @overload token_description(token)
# Uses current locale to get description of the given inflection +token+.
# @param [Symbol] token the identifier of a token
# @return [String,nil] the descriptive string or +nil+ if something
# went wrong (e.g. token was not found)
# @overload token_description(token, locale)
# Uses the given +locale+ to get description of the given inflection +token+.
# @param [Symbol,String] token the identifier of a token
# @param [Symbol] locale the locale to use
# @return [String,nil] the descriptive string or +nil+ if something
# went wrong (e.g. token was not found)
# @overload token_description(token, kind, locale)
# Uses the given +locale+ and +kind+ to get description of the given inflection +token+.
# @note If +kind+ begins with the +@+ symbol then the variant of this method
# operating on strict kinds will be called ({I18n::Inflector::API_Strict#token_description})
# @param [Symbol,String] token the identifier of a token
# @param [Symbol,String] kind the kind to narrow the results
# @param [Symbol] locale the locale to use
# @return [String,nil] the descriptive string or +nil+ if something
# went wrong (e.g. token was not found or +kind+ mismatched)
# @overload token_description(token, strict_kind)
# Uses the default locale and the given +kind+ (which name must begin with
# the +@+ symbol) to get description of the given inflection +token+.
# @note It calls {I18n::Inflector::API_Strict#token_description} on strict kinds data.
# @param [Symbol,String] token the identifier of a token
# @param [Symbol,String] strict_kind the kind of a token
# @param [Symbol] locale the locale to use
# @return [String,nil] the descriptive string or +nil+ if something
# went wrong (e.g. token was not found or +kind+ mismatched)
def token_description(*args)
token, kind, locale = tkl_args(args)
return nil if (token.nil? || token.to_s.empty?)
unless kind.nil?
kind = kind.to_s
return nil if kind.empty?
if kind[0..0] == Markers::STRICT_KIND
return strict.token_description(token, kind[1..-1], locale)
end
kind = kind.to_sym
end
data_safe(locale).get_description(token.to_sym, kind)
end
protected
# @private
def data(locale=nil)
@idb[prep_locale(locale)]
end
# @private
def data_safe(locale=nil)
@idb[prep_locale(locale)] || I18n::Inflector::InflectionData.new(locale)
end
# This method is the internal helper that prepares arguments
# containing +token+, +kind+ and +locale+.
#
# @note This method leaves +kind+ as is when it's +nil+ or empty. It sets
# +token+ to +nil+ when it's empty.
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @raise [ArgumentError] if the count of arguments is invalid
# @return [Array] the array containing
# cleaned and validated +token+, +kind+ and +locale+
# @overload tkl_args(token, kind, locale)
# Prepares arguments containing +token+, +kind+ and +locale+.
# @param [String,Hash] token the token
# @param [String,Hash] kind the inflection kind
# @param [String,Hash] locale the locale identifier
# @return [Array] the array containing
# cleaned and validated +token+, +kind+ and +locale+
# @overload tkl_args(token, locale)
# Prepares arguments containing +token+ and +locale+.
# @param [String,Hash] token the token
# @param [String,Hash] locale the locale identifier
# @return [Array] the array containing
# cleaned and validated +token+, +kind+ and +locale+
# @overload tkl_args(token)
# Prepares arguments containing +token+.
# @param [String,Hash] token the token
# @return [Array] the array containing
# cleaned and validated +token+ and the current locale
# @overload tkl_args(token, strict_kind)
# Prepares arguments containing +token+ and +strict_kind+.
# @param [String,Hash] token the token
# @param [String,Hash] strict_kind the strict kind identifier beginning with +@+ symbol
# @return [Array] the array containing
# cleaned and validated +token+, +strict_kind+ and the current locale
def tkl_args(args)
token, kind, locale = case args.count
when 1 then [args[0], nil, nil]
when 2 then args[1].to_s[0..0] == Markers::STRICT_KIND ? [args[0], args[1], nil] : [args[0], nil, args[1]]
when 3 then args
else raise I18n::ArgumentError.new("wrong number of arguments: #{args.count} for (1..3)")
end
[token,kind,locale]
end
end # class API
# @abstract This is for backward compatibility with the old naming scheme.
class Core < API
end
end # module Inflector
end # module I18n
i18n-inflector-2.6.7/lib/i18n-inflector/long_comments.rb 0000644 0000041 0000041 00000004525 13321144047 023026 0 ustar www-data www-data # encoding: utf-8
#
# Author:: Paweł Wilk (mailto:pw@gnu.org)
# Copyright:: (c) 2011,2012,2013 by Paweł Wilk
# License:: This program is licensed under the terms of {file:docs/LGPL GNU Lesser General Public License} or {file:docs/COPYING Ruby License}.
#
# This file contains inline documentation data
# that would make the file with code less readable
# if placed there. Code from this file is not used
# by the library, it's just for documentation.
module I18n
module Inflector
class API
# This reader allows to reach a reference of the
# object that is a kind of {I18n::Inflector::API_Strict}
# and handles inflections for named patterns (strict kinds).
#
# @api public
# @return [I18n::Inflector::API_Strict] the object containing
# database and operations for named patterns (strict kinds)
attr_reader :strict
# This reader allows to reach internal configuration
# of the engine. It is shared among all instances of
# the Inflector and also available as
# {I18n::Inflector::Config I18n::Inflector::Config}.
attr_reader :config
# Gets known regular inflection kinds.
#
# @api public
# @note To get all inflection kinds (regular and strict) for default inflector
# use: I18n.inflector.kinds + I18n.inflector.strict.kinds
# @return [Array] the array containing known inflection kinds
# @raise [I18n::InvalidLocale] if there is no proper locale name
# @overload kinds
# Gets known inflection kinds for the current locale.
# @return [Array] the array containing known inflection kinds
# @overload kinds(locale)
# Gets known inflection kinds for the given +locale+.
# @param [Symbol] locale the locale for which operation has to be done
# @return [Array] the array containing known inflection kinds
def kinds(locale=nil); super end
alias_method :inflection_kinds, :kinds
end
end
# @abstract This exception class is defined in package I18n. It is raised when
# the given and/or processed locale parameter is invalid.
class InvalidLocale; end
# @abstract This exception class is defined in package I18n. It is raised when
# the given and/or processed translation data or parameter are invalid.
class ArgumentError; end
end
i18n-inflector-2.6.7/lib/i18n-inflector/options.rb 0000644 0000041 0000041 00000031472 13321144047 021656 0 ustar www-data www-data # encoding: utf-8
#
# Author:: Paweł Wilk (mailto:pw@gnu.org)
# Copyright:: (c) 2011,2012,2013 by Paweł Wilk
# License:: This program is licensed under the terms of {file:docs/LGPL GNU Lesser General Public License} or {file:docs/COPYING Ruby License}.
#
# This file contains a class used to set up some options,
# for engine.
module I18n
module Inflector
# This class contains structures for keeping parsed translation data
# and basic operations.
#
# All global options are available for current backend's inflector by
# calling:
# I18n.backend.inflector.options.
# or just:
# I18n.inflector.options.
# A global option may be overriden by passing a proper option to
# the translation method. Such option should have the name of a
# global option but prefixed with +inflector_+:
# translate('welcome', :inflector_ => value)
# @note This class uses modified version of +attr_accessor+ that
# memorizes any added method name as an option name. These options
# (with +inflector_+ prefix added) are accessible through
# {#known} method. The last method is used by options preparing
# routine when the interpolation is performed.
class InflectionOptions
# Prefix used to mark option as a controlling option.
OPTION_PREFIX = 'inflector_'
class <options.options.prepare_options!(options) on the used backend,
# for example:
# I18n.backend.inflector.options.prepare(options)
# That will alter the +options+ data so they will contain all switches
# and values.
#
# @api public
# @return [Boolean] state of the switch
# @param [Boolean] state +true+ enables, +false+ disables this switch
attr_accessor :cache_aware
# This is a switch that enables extended error reporting. When it's enabled then
# errors are raised in case of unknown or empty tokens present in a pattern
# or in options. This switch is by default set to +false+.
#
# @note Local option +:inflector_raises+ passed
# to the {I18n::Backend::Inflector#translate} overrides this setting.
#
# @api public
# @return [Boolean] state of the switch
# @param [Boolean] state +true+ enables, +false+ disables this switch
attr_accessor :raises
# This is a switch that enables you to use aliases in patterns. When it's enabled then
# aliases may be used in inflection patterns, not only true tokens. This operation
# may make your translation data a bit messy if you're not alert.
# That's why this switch is by default set to +false+.
#
# @note Local option +:inflector_aliased_patterns+ passed to the
# {I18n::Backend::Inflector#translate} overrides this setting.
#
# @api public
# @return [Boolean] state of the switch
# @param [Boolean] state +true+ enables, +false+ disables this switch
attr_accessor :aliased_patterns
# This is a switch that enables you to interpolate patterns contained
# in resulting nested Hashes. It is used when the original translation
# method returns a subtree of translation data because the given key
# is not pointing to a leaf of the data but to some collection.
#
# This switch is by default set to +true+. When you turn it off then
# the Inflector won't touch nested results and will return them as they are.
#
# @note Local option +:inflector_traverses+ passed to the
# {I18n::Backend::Inflector#translate} overrides this setting.
#
# @api public
# @return [Boolean] state of the switch
# @param [Boolean] state +true+ enables, +false+ disables this switch
attr_accessor :traverses
# This is a switch that enables interpolation of symbols. Whenever
# interpolation method will receive a collection of symbols as a result
# of calling underlying translation method
# it won't process them, returning as they are, unless
# this switch is enabled.
#
# Note that using symbols as values in translation data creates
# I18n aliases. This option is intended to work with arrays of
# symbols or hashes with symbols as values, if the original translation
# method returns such structures.
#
# This switch is by default set to +false+.
#
# @note Local option +:inflector_interpolate_symbols+ passed to the
# {I18n::Backend::Inflector#translate} overrides this setting.
#
# @api public
# @return [Boolean] state of the switch
# @param [Boolean] state +true+ enables, +false+ disables this switch
attr_accessor :interpolate_symbols
# When this switch is set to +true+ then inflector falls back to the default
# token for a kind if an inflection option passed to the
# {I18n::Backend::Inflector#translate} is unknown or +nil+.
# Note that the value of the default token will be
# interpolated only when this token is present in a pattern. This switch
# is by default set to +true+.
#
# @note Local option +:inflector_unknown_defaults+ passed
# to the {I18n::Backend::Inflector#translate} overrides this setting.
#
# @api public
# @return [Boolean] state of the switch
# @param [Boolean] state +true+ enables, +false+ disables this switch
#
# @example YAML:
# en:
# i18n:
# inflections:
# gender:
# n: 'neuter'
# o: 'other'
# default: n
#
# welcome: "Dear @{n:You|o:Other}"
# welcome_free: "Dear @{n:You|o:Other|Free}"
#
# @example Example 1
#
# # :gender option is not present,
# # unknown tokens in options are falling back to default
#
# I18n.t('welcome')
# # => "Dear You"
#
# # :gender option is not present,
# # unknown tokens from options are not falling back to default
#
# I18n.t('welcome', :inflector_unknown_defaults => false)
# # => "Dear You"
#
# # other way of setting an option – globally
#
# I18n.inflector.options.unknown_defaults = false
# I18n.t('welcome')
# # => "Dear You"
#
# # :gender option is not present, free text is present,
# # unknown tokens from options are not falling back to default
#
# I18n.t('welcome_free', :inflector_unknown_defaults => false)
# # => "Dear You"
#
# @example Example 2
#
# # :gender option is nil,
# # unknown tokens from options are falling back to default token for a kind
#
# I18n.t('welcome', :gender => nil)
# # => "Dear You"
#
# # :gender option is nil
# # unknown tokens from options are not falling back to default token for a kind
#
# I18n.t('welcome', :gender => nil, :inflector_unknown_defaults => false)
# # => "Dear "
#
# # :gender option is nil, free text is present
# # unknown tokens from options are not falling back to default token for a kind
#
# I18n.t('welcome_free', :gender => nil, :inflector_unknown_defaults => false)
# # => "Dear Free"
#
# @example Example 3
#
# # :gender option is unknown,
# # unknown tokens from options are falling back to default token for a kind
#
# I18n.t('welcome', :gender => :unknown_blabla)
# # => "Dear You"
#
# # :gender option is unknown,
# # unknown tokens from options are not falling back to default token for a kind
#
# I18n.t('welcome', :gender => :unknown_blabla, :inflector_unknown_defaults => false)
# # => "Dear "
#
# # :gender option is unknown, free text is present
# # unknown tokens from options are not falling back to default token for a kind
#
# I18n.t('welcome_free', :gender => :unknown_blabla, :inflector_unknown_defaults => false)
# # => "Dear Free"
attr_accessor :unknown_defaults
# When this switch is set to +true+ then inflector falls back to the default
# token for a kind if the given inflection option is correct but doesn't exist
# in a pattern.
#
# There might happen that the inflection option
# given to {#translate} method will contain some proper token, but that token
# will not be present in a processed pattern. Normally an empty string will
# be generated from such a pattern or a free text (if a local fallback is present
# in a pattern). You can change that behavior and tell interpolating routine to
# use the default token for a processed kind in such cases.
#
# This switch is by default set to +false+.
#
# @note Local option +:inflector_excluded_defaults+ passed to the {I18n::Backend::Inflector#translate}
# overrides this setting.
#
# @api public
# @return [Boolean] state of the switch
# @param [Boolean] state +true+ enables, +false+ disables this switch
#
# @example YAML:
# en:
# i18n:
# inflections:
# gender:
# o: "other"
# m: "male"
# n: "neuter"
# default: n
#
# welcome: 'Dear @{n:You|m:Sir}'
# @example Usage of +:inflector_excluded_defaults+ option
# I18n.t('welcome', :gender => :o)
# # => "Dear "
#
# I18n.t('welcome', :gender => :o, :inflector_excluded_defaults => true)
# # => "Dear You"
attr_accessor :excluded_defaults
# This method initializes all internal structures.
def initialize
reset
end
# This method resets all options to their default values.
#
# @return [void]
def reset
@unknown_defaults = true
@traverses = true
@interpolate_symbols= false
@excluded_defaults = false
@aliased_patterns = false
@cache_aware = false
@raises = false
nil
end
# This method processes the given argument
# in a way that it will use default values
# for options that are missing.
#
# @api public
# @note It modifies the given object.
# @param [Hash] options the options
# @return [Hash] the given options
def prepare_options!(options)
self.class.known.
reject { |name,long| options.has_key?(long) }.
each { |name,long| options[long] = instance_variable_get(name) }
options
end
# This method prepares options for translate method.
# That means removal of all kind-related options
# and all options that are flags.
#
# @api public
# @note It modifies the given object.
# @param [Hash] options the given options
# @return [Hash] the given options
def clean_for_translate!(options)
self.class.known.each { |name,long| options.delete long }
options
end
# Lists all known options in a long format
# (each name preceeded by inflector_).
#
# @api public
# @return [Array] the known options
def known
self.class.known.values
end
end
end
end
i18n-inflector-2.6.7/lib/i18n-inflector/backend.rb 0000644 0000041 0000041 00000035761 13321144047 021557 0 ustar www-data www-data # encoding: utf-8
#
# Author:: Paweł Wilk (mailto:pw@gnu.org)
# Copyright:: (c) 2011,2012,2013 by Paweł Wilk
# License:: This program is licensed under the terms of {file:docs/LGPL GNU Lesser General Public License} or {file:docs/COPYING Ruby License}.
#
# This file contains I18n::Backend::Inflector module,
# which extends I18n::Backend::Simple by adding the ability
# to interpolate patterns containing inflection tokens
# defined in translation data.
module I18n
# @abstract This namespace is shared with I18n subsystem.
module Backend
# This module contains methods that add
# tokenized inflection support to internal I18n classes.
# It is intened to be included in the Simple backend
# module so that it will patch translate method in order
# to interpolate additional inflection tokens present in translations.
# Usually you don't have to know what's here to use it.
module Inflector
# Shortcut to configuration module.
InflectorCfg = I18n::Inflector::Config
# This accessor allows to reach API methods of the
# inflector object associated with this class.
def inflector
inflector_try_init
@inflector
end
# Cleans up internal hashes containg kinds, inflections and aliases.
#
# @api public
# @note It calls {I18n::Backend::Simple#reload! I18n::Backend::Simple#reload!}
# @return [Boolean] the result of calling ancestor's method
def reload!
@inflector = nil
super
end
# Translates given key taking care of inflections.
#
# @api public
# @see I18n::Inflector::API#interpolate
# @see I18n::Inflector::InflectionOptions
# @param [Symbol] locale locale
# @param [Symbol,String] key translation key
# @param [Hash] options a set of options to pass to the translation routines.
# @note The given +options+ along with a translated string and the given
# +locale+ are passed to
# {I18n::Backend::Simple#translate I18n::Backend::Simple#translate}
# and then the result is processed by {I18n::Inflector::API#interpolate}
# @return [String] the translated string with interpolated patterns
def translate(locale, key, options = {})
inflector_try_init
# take care about cache-awareness
cached = options.has_key?(:inflector_cache_aware) ?
options[:inflector_cache_aware] : @inflector.options.cache_aware
if cached
interpolate_options = options
@inflector.options.prepare_options!(options)
else
interpolate_options = options.dup
@inflector.options.clean_for_translate!(options)
end
# translate string using original translate
translated_string = super
# generate a pattern from key-based inflection object
if (translated_string.is_a?(Hash) && key.to_s[0..0] == InflectorCfg::Markers::STRICT_KIND)
translated_string = @inflector.key_to_pattern(translated_string)
end
# interpolate string
begin
@inflector.options.prepare_options!(interpolate_options) unless cached
@inflector.interpolate(translated_string, locale, interpolate_options)
# complete the exception by adding translation key
rescue I18n::InflectionException => e
e.key = key
raise
end
end
# Stores translations in memory.
#
# @api public
# @raise [I18n::InvalidLocale] if the given +locale+ is invalid
# @raise [I18n::BadInflectionToken] if a name of some loaded token is invalid
# @raise [I18n::BadInflectionAlias] if a loaded alias points to a token that does not exists
# @raise [I18n::BadInflectionKind] if a loaded kind identifier is invalid
# @raise [I18n::DuplicatedInflectionToken] if a token has already appeard in loaded configuration
# @note If inflections are changed it will regenerate proper internal
# structures.
# @return [Hash] the stored translations
def store_translations(locale, data, options = {})
r = super
inflector_try_init
if data.respond_to?(:has_key?)
subdata = (data[:i18n] || data['i18n'])
unless subdata.nil?
subdata = (subdata[:inflections] || subdata['inflections'])
unless subdata.nil?
db, db_strict = load_inflection_tokens(locale, r[:i18n][:inflections])
@inflector.add_database(db, db_strict)
end
end
end
r
end
protected
# Initializes internal hashes used for keeping inflections configuration.
#
# @return [void]
def inflector_try_init
unless (defined?(@inflector) && !@inflector.nil?)
@inflector = I18n::Inflector::API.new
init_translations unless initialized?
end
end
# Takes care of loading inflection tokens
# for all languages (locales) that have them
# defined.
#
# @note It calls {I18n::Backend::Simple#init_translations I18n::Backend::Simple#init_translations}
# @raise [I18n::BadInflectionToken] if a name of some loaded token is invalid
# @raise [I18n::BadInflectionAlias] if a loaded alias points to a token that does not exists
# @raise [I18n::BadInflectionKind] if a loaded kind identifier is invalid
# @raise [I18n::DuplicatedInflectionToken] if a token has already appeard in loaded configuration
# @return [Boolean] +true+ if everything went fine
def init_translations
unless (defined?(@inflector) && !@inflector.nil?)
@inflector = I18n::Inflector::API.new
end
super
end
# Gives an access to the internal structure containing configuration data
# for the given locale.
#
# @note Under some very rare conditions this method may be called while
# translation data is loading. It must always return when translations
# are not initialized. Otherwise it will cause loops and someone in Poland
# will eat a kittien!
# @param [Symbol] locale the locale to use
# @return [Hash,nil] part of the translation data that
# reflects inflections for the given locale or +nil+
# if translations are not initialized
def inflection_subtree(locale)
return nil unless initialized?
lookup(locale, :"i18n.inflections", [], :fallback => true, :raise => :false)
end
# Resolves an alias for a token if the given +token+ is an alias.
#
# @note It does take care of aliasing loops (max traverses is set to 64).
# @raise [I18n::BadInflectionToken] if a name of the token that alias points to is corrupted
# @raise [I18n::BadInflectionAlias] if an alias points to token that does not exists
# @return [Symbol] the true token that alias points to if the given +token+
# is an alias or the given +token+ if it is a true token
# @overload shorten_inflection_alias(token, kind, locale)
# Resolves an alias for a token if the given +token+ is an alias for the given +locale+ and +kind+.
# @note This version uses internal subtree and needs the translation data to be initialized.
# @param [Symbol] token the token name
# @param [Symbol] kind the kind of the given token
# @param [Symbol] locale the locale to use
# @return [Symbol] the true token that alias points to if the given +token+
# is an alias or the given +token+ if it is a true token
# @overload shorten_inflection_alias(token, kind, locale, subtree)
# Resolves an alias for a token if the given +token+ is an alias for the given +locale+ and +kind+.
# @param [Symbol] token the token name
# @param [Symbol] kind the kind of the given token
# @param [Symbol] locale the locale to use
# @param [Hash] subtree the tree (in a form of nested Hashes) containing inflection tokens to scan
# @return [Symbol] the true token that alias points to if the given +token+
# is an alias or the given +token+ if it is a true token
def shorten_inflection_alias(token, kind, locale, subtree=nil, count=0)
count += 1
return nil if count > 64
inflections_tree = subtree || inflection_subtree(locale)
return nil if (inflections_tree.nil? || inflections_tree.empty?)
kind_subtree = inflections_tree[kind]
value = kind_subtree[token].to_s
if value[0..0] != InflectorCfg::Markers::ALIAS
if kind_subtree.has_key?(token)
return token
else
raise I18n::BadInflectionToken.new(locale, token, kind)
end
else
orig_token = token
token = value[1..-1]
if InflectorCfg::Reserved::Tokens.invalid?(token, :DB)
raise I18n::BadInflectionToken.new(locale, token, kind)
end
token = token.to_sym
if kind_subtree[token].nil?
raise BadInflectionAlias.new(locale, orig_token, kind, token)
else
shorten_inflection_alias(token, kind, locale, inflections_tree, count)
end
end
end
# Uses the inflections subtree and creates internal mappings
# to resolve kinds assigned to inflection tokens and aliases, including defaults.
# @return [I18n::Inflector::InflectionData,nil] the database containing inflections tokens
# or +nil+ if something went wrong
# @raise [I18n::BadInflectionToken] if a token identifier is invalid
# @raise [I18n::BadInflectionKind] if a kind identifier is invalid
# @raise [I18n::BadInflectionAlias] if a loaded alias points to a token that does not exists
# @raise [I18n::DuplicatedInflectionToken] if a token has already appeard in loaded configuration
# @overload load_inflection_tokens(locale)
# @note That version calls the {inflection_subtree} method to obtain internal translations data.
# Loads inflection tokens for the given locale using internal hash of stored translations. Requires
# translations to be initialized.
# @param [Symbol] locale the locale to use and work for
# @return [I18n::Inflector::InflectionData,nil] the database containing inflections tokens
# or +nil+ if something went wrong
# @overload load_inflection_tokens(locale, subtree)
# Loads inflection tokens for the given locale using datthe given in an argument
# @param [Symbol] locale the locale to use and work for
# @param [Hash] subtree the tree (in a form of nested Hashes) containing inflection tokens to scan
# @return [I18n::Inflector::InflectionData,nil] the database containing inflections tokens
# or +nil+ if something went wrong
def load_inflection_tokens(locale, subtree=nil)
inflections_tree = subtree || inflection_subtree(locale)
return nil if (inflections_tree.nil? || inflections_tree.empty?)
inflections_tree = deep_symbolize(inflections_tree)
idb = I18n::Inflector::InflectionData.new(locale)
idb_strict = I18n::Inflector::InflectionData_Strict.new(locale)
return nil if (idb.nil? || idb_strict.nil?)
inflections = prepare_inflections(locale, inflections_tree, idb, idb_strict)
# add inflection tokens and kinds to internal database
inflections.each do |orig_kind, kind, strict_kind, subdb, tokens|
# validate token's kind
if (kind.to_s.empty? || InflectorCfg::Reserved::Kinds.invalid?(orig_kind, :DB))
raise I18n::BadInflectionKind.new(locale, orig_kind)
end
tokens.each_pair do |token, description|
# test for duplicate
if subdb.has_token?(token, strict_kind)
raise I18n::DuplicatedInflectionToken.new(locale, token, orig_kind,
subdb.get_kind(token, strict_kind))
end
# validate token's name
if InflectorCfg::Reserved::Tokens.invalid?(token, :DB)
raise I18n::BadInflectionToken.new(locale, token, orig_kind)
end
# validate token's description
if description.nil?
raise I18n::BadInflectionToken.new(locale, token, orig_kind, description)
elsif description.to_s[0..0] == InflectorCfg::Markers::ALIAS
next
end
# skip default token for later processing
next if token == :default
subdb.add_token(token, kind, description)
end
end
# handle aliases
inflections.each do |orig_kind, kind, strict_kind, subdb, tokens|
tokens.each_pair do |token, description|
next if token == :default
next if description.to_s[0..0] != InflectorCfg::Markers::ALIAS
real_token = shorten_inflection_alias(token, orig_kind, locale, inflections_tree)
subdb.add_alias(token, real_token, kind) unless real_token.nil?
end
end
# handle default tokens
inflections.each do |orig_kind, kind, strict_kind, subdb, tokens|
next unless tokens.has_key?(:default)
if subdb.has_default_token?(kind)
raise I18n::DuplicatedInflectionToken.new(locale, :default, kind, orig_kind)
end
orig_target = tokens[:default]
target = orig_target.to_s
target = target[1..-1] if target[0..0] == InflectorCfg::Markers::ALIAS
if target.empty?
raise I18n::BadInflectionToken.new(locale, token, orig_kind, orig_target)
end
target = subdb.get_true_token(target.to_sym, kind)
if target.nil?
raise I18n::BadInflectionAlias.new(locale, :default, orig_kind, orig_target)
end
subdb.set_default_token(kind, target)
end
[idb, idb_strict]
end
# @private
def prepare_inflections(locale, inflections, idb, idb_strict)
unless inflections.respond_to?(:has_key?)
raise I18n::BadInflectionKind.new(locale, :INFLECTIONS_ROOT)
end
I18n::Inflector::LazyHashEnumerator.for(inflections).ary_map do |kind, tokens|
next if (tokens.nil? || tokens.empty?)
unless tokens.respond_to?(:has_key?)
raise I18n::BadInflectionKind.new(locale, kind)
end
subdb = idb
strict_kind = nil
orig_kind = kind
if kind.to_s[0..0] == InflectorCfg::Markers::STRICT_KIND
kind = kind.to_s[1..-1]
next if kind.empty?
kind = kind.to_sym
subdb = idb_strict
strict_kind = kind
end
[orig_kind, kind, strict_kind, subdb, tokens]
end
end
# @private
def deep_symbolize(obj)
obj.inject({}) do |result, (key, value)|
value = deep_symbolize(value) if value.is_a?(Hash)
result[(key.to_s.to_sym rescue key) || key] = value
result
end
end
end # module Inflector
end # module Backend
end # module I18n
i18n-inflector-2.6.7/lib/i18n-inflector/inflector.rb 0000644 0000041 0000041 00000002317 13321144047 022144 0 ustar www-data www-data # encoding: utf-8
#
# Author:: Paweł Wilk (mailto:pw@gnu.org)
# Copyright:: (c) 2011,2012,2013 by Paweł Wilk
# License:: This program is licensed under the terms of {file:docs/LGPL GNU Lesser General Public License} or {file:docs/COPYING Ruby License}.
#
# This file contains a stub of I18n::Inflector module,
# which extends I18n by adding the ability
# to interpolate patterns containing inflection tokens
# defined in translation data and manipulate on that data.
module I18n
class <