diff --git a/README.md b/README.md
index e4de52c4e..79c664060 100644
--- a/README.md
+++ b/README.md
@@ -42,7 +42,7 @@ Please check the [Benchmarks and Memory Profiles Source](http://github.com/ddnex
- Pagy has a very slim core code of just ~100 line of simple ruby, organized in 3 flat modules very easy to understand and use _(see [more...](https://ddnexus.github.io/pagy/api))_
- It has a quite fat set of optional extras that you can explicitly require for very efficient and modular customization _(see [extras](https://ddnexus.github.io/pagy/extras))_
-- It has no dependencies: it produces its own HTML, URLs, pluralization and interpolation with its own specialized and fast code _(see [why...](https://ddnexus.github.io/pagy/index#specialized-code-instead-of-generic-helpers))_
+- It has no dependencies: it produces its own HTML, URLs, i18n with its own specialized and fast code _(see [why...](https://ddnexus.github.io/pagy/index#specialized-code-instead-of-generic-helpers))_
- 100% of its methods are public API, accessible and overridable **right where you use them** (no need of monkey-patching)
- 100% test coverage for core code and extras
diff --git a/docs/api/frontend.md b/docs/api/frontend.md
index 57a133cd9..94a04d805 100644
--- a/docs/api/frontend.md
+++ b/docs/api/frontend.md
@@ -160,84 +160,73 @@ This method is similar to the `I18n.t` and its equivalent rails `t` helper. It i
**IMPORTANT**: if you are using pagy with some language missing from the [dictionary files](https://github.com/ddnexus/pagy/blob/master/lib/locales), please, submit your translation!
-Pagy is I18n ready. That means that all its strings are stored in a dictionary file of one of its [languages](https://github.com/ddnexus/pagy/blob/master/lib/locales), ready to be customized and/or translated/pluralized and used with or without the `I18n` gem.
+Pagy is i18n ready. That means that all its strings are stored in the dictionary files of its [locales](https://github.com/ddnexus/pagy/blob/master/lib/locales), ready to be customized and/or used with or without the `I18n` gem.
-A Pagy dictionary file is a YAML file containing a few entries used in the the UI by helpers and templates through the [pagy_t method](#pagy_tpath-vars) (eqivalent to the `I18n.t` or rails `t` helper). The file follows the same structure of the standard locale files for `i18n`.
+**Notice**: a Pagy dictionary file is a YAML file containing a few entries used internally in the the UI by helpers and templates through the [pagy_t](#pagy_tpath-vars) method. The file follows the same structure of the standard locale files for the `i18n` gem.
-### Multi-language apps
+### Pagy I18n implementation
-For multi-language apps you need the dynamic translation provided by the [i18n extra](../extras/i18n.md), which delegates the handling of the pagy strings to the `I18n` gem. In that case you need only to require the I18n extra in the initializer file.
+The pagy internal i18n implementation is ~12x faster and uses ~6x less memory than the standard `i18n` gem.
-**Notice**: For simplicity, you could also use the `i18n` extra for single-language apps, but if you want more performance, please follow the specific documentation below.
+Since Pagy version 2.0, you can use it for both single-language and multi-language apps, with or without the `i18n` gem.
-### Single-language apps
+Notice: if your app is using i18n, it will work independently from it.
-Single-language apps (i.e. only `fr` or only `en` or only ...) don't need to switch between languages, so they don't need the `i18n` extra/`I18n` gem (although you could choose to use it).
+The pagy internal i18n is implemented around the `Pagy::I18n` constant hash which contains the locales data needed to pagy and your app. You may need to configure it in the [pagy.rb](https://github.com/ddnexus/pagy/blob/master/lib/config/pagy.rb) initializer.
-By default, Pagy handles its own dictionary file directly, providing pluralization and interpolation (without dynamic translation) _5x faster_ and using _3.5x less memory_ than the standard `I18n` gem.
+#### Pagy::I18n.load configuration
-If you are fine with the locales provided with pagy, you just need to load the dictionary file of your language by adding this line the initializer file. For example with `zh-cn`:
+By default pagy will render its output using the built-in `en` locale. If your app uses only `en` and you are fine with the built-in strings, you are done without configuring anything at all.
-```ruby
-Pagy::Frontend::I18N.load(file: Pagy.root.join('locales', 'zh-cn.yml'), language:'zh-cn')
-```
-
-If you need to use your own translation file and/or customize the Pagy strings in this scenario, you may need the following steps:
-
-1. copy and edit one of the [dictionary files](https://github.com/ddnexus/pagy/blob/master/lib/locales)
-2. load it in the initializer file (e.g. `Pagy::Frontend::I18N.load(file:..., language:'tr')`
-3. see [Adding the model translations](#adding-the-model-translations) below
-4. check if you need to configure some of the following variables in the [pagy.rb](https://github.com/ddnexus/pagy/blob/master/lib/config/pagy.rb) initializer.
-
-#### Pagy::Frontend::I18N Constant
+If you need to load different built-in locales, and/or custom dictionary files or even non built-in languages and pluralizations, you can do it all by passing a few arguments to the `Pagy::I18n.load` method.
-**IMPORTANT**: This variable has no effect if you use the `i18n` extra.
+**Notice**: the `Pagy::I18n.load` method is intended to be used once in the [pagy.rb](https://github.com/ddnexus/pagy/blob/master/lib/config/pagy.rb) initializer. If you use it multiple times, the last statement will override the previous statements.
-The `Pagy::Frontend::I18N` constant is the core of the Pagy I18n implementation. This constant allows to control the dictionary file, the language to load and the pluralization proc.
+Here are a few examples that should cover all the possible confgurations:
-#### Pagy::Frontend::I18N.load(file:..., language:'en')
+```rb
+# IMPORTANT: use only one load statement
-**IMPORTANT**: This method has no effect if you use the `i18n` extra.
+# load the "de" built-in locale:
+Pagy::I18n.load(locale: 'de')
-It allows to load a built-in language (different than the default 'en') and/or a custom dictionary file, different from `Pagy.root.join('locales', 'pagy.yml')`. It is tipically used in the Pagy initializer file _(see [Configuration](../how-to.md#global-configuration))_. For example:
+# load the "de" locale defined in the custom file at :filepath:
+Pagy::I18n.load(locale: 'de', filepath: 'path/to/pagy-de.yml')
-```ruby
-# this would load the Italian variant of the built-in dictionary
-Pagy::Frontend::I18N.load(language:'it')
-
-# this would load the default English variant of 'path/to/dictionary.yml'
-Pagy::Frontend::I18N.load(file:'path/to/dictionary.yml')
-
-# this would load the Italian variant of 'path/to/dictionary.yml'
-Pagy::Frontend::I18N.load(file:'path/to/dictionary.yml', language:'it')
+# load the "de", "en" and "es" built-in locales:
+# the first :locale will be used also as the default_locale
+Pagy::I18n.load({locale: 'de'},
+ {locale: 'en'},
+ {locale: 'es'})
+
+# load the "en" built-in locale, a custom "es" locale, and a totally custom locale complete with the :pluralize proc:
+Pagy::I18n.load({locale: 'en'},
+ {locale: 'es', filepath: 'path/to/pagy-es.yml'},
+ {locale: 'xyz', # not built-in
+ filepath: 'path/to/pagy-xyz.yml',
+ pluralize: lambda{|count| ... } )
```
-**Notice**: the Pagy implementation of I18n is designed to speedup single-language apps and does not provide dynamic translation, so the `language` is statically loaded at startup-time and cannot be changed. Use the `i18n` extra if you need dynamic translation.
-
-#### Pagy::Frontend::I18N[:plural]
+**Notice**: You should use a custom `:pluralize` proc only for pluralization types not included in the built-in [p11n.rb](https://github.com/ddnexus/pagy/blob/master/lib/locales/utils/p11n.rb)
+ rules. In that case, please submit a PR with your dictionary file and plural rule. The `:pluralize` proc should receive the `count` as a single argument and should return the plural type string (e.g. something like `'zero'`, `'one'` or `'other'`, depending on the passed count).
-**IMPORTANT**: This variable has no effect if you use the `i18n` extra.
+#### Set the request locale in multi-language apps
-This variable controls the internal pluralization.
+When you configure multiple locales, you must also set the locale for each request. You usually do that in the application controller, by checking the `:locale` param. For example, in a rails app you should do something like:
-Pagy tries to set the language plural proc when you use the `Pagy::Frontend::I18N.load` method, by loading the built-in plural for the language. _(see [plurals.rb](https://github.com/ddnexus/pagy/blob/master/lib/locales/plurals.rb))_
-
-If there is no rule defined for the language loaded, the variable is set to the `:zero_one_other` plural rule (default for English language).
-
-If your custom language requires a pluralization different than `:zero_one_other`, you should define a custom rule. For example:
-
-```ruby
-# this would apply a custom pluralization rule to the current loaded dictionary
-Pagy::Frontend::I18N[:plural] = -> (count) {|count| ...}
+```rb
+before_action { @pagy_locale = params[:locale] || 'en' }
```
-The custom proc should receive the `count` as a single argument and should return the plural type string (e.g. something like `'zero'`, `'one'` or `'other'`, depending on the passed count). You should customize it only for pluralization types not included in the built-in plural rules. In that case, please submit a PR with your dictionary file and plural rule. Thanks.
+That instance variable will be used by the [pagy_t](#pagy_tpath-vars) method included in your view and will translate the pagy strings to the selected locale.
+
+**Notice**: In case of `@pagy_locale.nil?` or unknown/not-loaded, then the first loaded locale will be used for the translation. That means that you don't have to set the `@pagy_locale` variable if your app uses just a single locale.
#### Adding the model translations
-When Pagy uses its own handling of the dictionary file, it has only access to the strings in its own file and not in other `I18n` files used by the rest of the app.
+When Pagy uses its own i18n implementation, it has only access to the strings in its own files and not in other `I18n` files used by the rest of the app.
-That means that if you use the `pagy_info` helper with the specific model names instead of the generic "items" string, you may need to add entries for the models in the pagy dictionary file. For example:
+That means that if you use the `pagy_info` helper with the specific model names instead of the generic "items" string, you may need to add entries for the models in the pagy dictionary files. For example:
```yaml
en:
@@ -255,3 +244,10 @@ en:
```
_(See also the [pagy_info method](#pagy_infopagy))_
+
+
+### Using the I18n gem
+
+If - despite the disadvantages - you want to use the standard `i18n` gem in place of the pagy i18n implementation, you should use the [i18n extra](../extras/i18n.md), which delegates the handling of the pagy strings to the `i18n` gem. In that case you need only to require the extra in the initializer file with `require 'pagy/extras/i18n'` and everything will be handled by the `i18n` gem.
+
+ **Notice**: if you use the [i18n extra](../extras/i18n.md)/`i18n` gem, you don't need any of the above configurations.
diff --git a/docs/extras/i18n.md b/docs/extras/i18n.md
index 5ef11970e..c12c3fcd6 100644
--- a/docs/extras/i18n.md
+++ b/docs/extras/i18n.md
@@ -3,7 +3,11 @@ title: I18n
---
# I18n Extra
-The `i18n` extra overrides the `pagy_t` method so it uses `I18n.t`. Use this extra only with multi-language apps since the `I18n` gem adds quite an overhead and slowers down Pagy.
+**Notice**: Since Pagy version 2.0, you can use the pagy `i18n` implementation for both single-language and multi-language apps, with or without the `i18n` gem.
+
+The `i18n` extra overrides the `pagy_t` method so it uses `I18n.t` implemented by the `i18n` gem.
+
+The `I18n.t` is ~12x slower and uses ~6x more memory than `pagy_t` so use it wisely.
See also [I18n](../api/frontend.md#i18n).
diff --git a/docs/how-to.md b/docs/how-to.md
index 190c3bfaf..fe29b37b6 100644
--- a/docs/how-to.md
+++ b/docs/how-to.md
@@ -327,7 +327,7 @@ By default Pagy generates all the page links including the `page` param. If you
## Using Templates
-The `pagy_nav*` helpers are optimized for speed, and they are really fast. On the other hand editing a template might be easier when you have to customize the rendering, however every template system adds some inevitable overhead and it will be about 40-80% slower than using the related helper. That will still be dozens of times faster than the other gems, but... you should choose wisely.
+The `pagy_nav*` helpers are optimized for speed, and they are really fast. On the other hand editing a template might be easier when you have to customize the rendering, however every template system adds some inevitable overhead and it will be about 30-70% slower than using the related helper. That will still be dozens of times faster than the other gems, but... you should choose wisely.
Pagy provides the replacement templates for the `pagy_nav`, `pagy_bootstrap_nav`, `pagy_bulma_nav` and the `pagy_foundation_nav` helpers (available with the relative extras) in 3 flavors: `erb`, `haml` and `slim`.
diff --git a/lib/config/pagy.rb b/lib/config/pagy.rb
index 1172ecd68..7b12fc38e 100644
--- a/lib/config/pagy.rb
+++ b/lib/config/pagy.rb
@@ -1,5 +1,5 @@
# Pagy initializer file
-# Customize only what you really need but notice that Pagy works also without any of the following lines.
+# Customize only what you really need and notice that Pagy works also without any of the following lines.
# Extras
@@ -111,15 +111,34 @@
# I18n
-# I18n faster internal pagy implementation (does not use the I18n gem)
-# Use only for single language apps that don't need dynamic translation between multiple languages
+# Pagy internal I18n: ~12x faster using ~6x less memory than the i18n gem
# See https://ddnexus.github.io/pagy/api/frontend#i18n
-# Notice: Do not use any of the following lines if you use the i18n extra below
-# Pagy::Frontend::I18N.load(file: Pagy.root.join('locale', 'es.yml'), language:'es') # load 'es' pagy language file
-# Pagy::Frontend::I18N.load(file:'path/to/dictionary.yml', language:'en') # load a custom 'en' file
-# Pagy::Frontend::I18N[:plural] = -> (count) {(['zero', 'one'][count] || 'other')} # default
-
-# I18n extra: Use the `I18n` gem instead of the pagy implementation
-# (slower but allows dynamic translation between multiple languages)
+# Notice: No need to use any of the following lines if you use the i18n extra below
+#
+# Examples:
+# load the "de" built-in locale:
+# Pagy::I18n.load(locale: 'de')
+#
+# load the "de" locale defined in the custom file at :filepath:
+# Pagy::I18n.load(locale: 'de', filepath: 'path/to/pagy-de.yml')
+#
+# load the "de", "en" and "es" built-in locales:
+# (the first passed :locale will be used also as the default_locale)
+# Pagy::I18n.load({locale: 'de'},
+# {locale: 'en'},
+# {locale: 'es'})
+#
+# load the "en" built-in locale, a custom "es" locale,
+# and a totally custom locale complete with the :pluralize proc:
+# (the first passed :locale will be used also as the default_locale)
+# Pagy::I18n.load({locale: 'en'},
+# {locale: 'es', filepath: 'path/to/pagy-es.yml'},
+# {locale: 'xyz', # not built-in
+# filepath: 'path/to/pagy-xyz.yml',
+# pluralize: lambda{|count| ... } )
+
+
+# I18n extra: uses the standard i18n gem which is ~12x slower using ~6x more memory
+# than the default pagy internal i18n (see above)
# See https://ddnexus.github.io/pagy/extras/i18n
# require 'pagy/extras/i18n'
diff --git a/lib/locales/utils/i18n.rb b/lib/locales/utils/i18n.rb
new file mode 100644
index 000000000..242b330a7
--- /dev/null
+++ b/lib/locales/utils/i18n.rb
@@ -0,0 +1,17 @@
+# See https://ddnexus.github.io/pagy/api/frontend#i18n
+# frozen_string_literal: true
+
+# this file returns the I18n hash used as default alternative to the i18n gem
+
+Hash.new{|h,_| h.first[1]}.tap do |i18n| # first loaded locale used as default
+ i18n.define_singleton_method(:load) do |*args|
+ # eval: we don't need to keep the loader proc in memory
+ eval(Pagy.root.join('locales', 'utils', 'loader.rb').read).call(i18n, *args) #rubocop:disable Security/Eval
+ end
+ i18n.define_singleton_method(:t) do |locale, path, vars={}|
+ data, pluralize = self[locale]
+ translate = data[path] || vars[:count] && data[path+=".#{pluralize.call(vars[:count])}"] or return %([translation missing: "#{path}"])
+ translate.call(vars)
+ end
+ i18n.load(locale: 'en')
+end
diff --git a/lib/locales/utils/loader.rb b/lib/locales/utils/loader.rb
new file mode 100644
index 000000000..01180de1c
--- /dev/null
+++ b/lib/locales/utils/loader.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+# the whole file will be eval'ed/executed and gc-collected after returning/executing the loader proc
+
+# eval: no need for the whole file in memory
+p11n = eval(Pagy.root.join('locales', 'utils', 'p11n.rb').read) #rubocop:disable Security/Eval
+
+# flatten the dictionary file nested keys
+# convert each value to a simple ruby interpolation proc
+flatten = lambda do |hash, key=''|
+ hash.each.reduce({}) do |h, (k, v)|
+ v.is_a?(Hash) \
+ ? h.merge!(flatten.call(v, "#{key}#{k}."))
+ : h.merge!(eval %({"#{key}#{k}" => lambda{|vars|"#{v.gsub(/%{[^}]+?}/){|m| "\#{vars[:#{m[2..-2]}]||'#{m}'}" }}"}})) #rubocop:disable Security/Eval
+ end
+ end
+
+# loader proc
+lambda do |i18n, *args|
+ i18n.clear
+ args.each do |arg|
+ arg[:filepath] ||= Pagy.root.join('locales', "#{arg[:locale]}.yml")
+ arg[:pluralize] ||= p11n[arg[:locale]]
+ hash = YAML.load(File.read(arg[:filepath], encoding: 'UTF-8')) #rubocop:disable Security/YAMLLoad
+ hash.key?(arg[:locale]) or raise ArgumentError, %(Pagy::I18n.load: :locale "#{arg[:locale]}" not found in :filepath "#{arg[:filepath].inspect}")
+ i18n[arg[:locale]] = [flatten.call(hash[arg[:locale]]), arg[:pluralize]]
+ end
+end
diff --git a/lib/locales/plurals.rb b/lib/locales/utils/p11n.rb
similarity index 66%
rename from lib/locales/plurals.rb
rename to lib/locales/utils/p11n.rb
index 0ac24ed06..6f92f8d5c 100644
--- a/lib/locales/plurals.rb
+++ b/lib/locales/utils/p11n.rb
@@ -1,7 +1,9 @@
-# This file adds support for multiple built-in plualization types.
-# It defines the pluralization procs and gets eval(ed) at I18N.load time.
+# See https://ddnexus.github.io/pagy/api/frontend#i18n
# frozen_string_literal: true
+# This file adds support for multiple built-in plualization types.
+# It defines the pluralization procs and gets eval(ed) and gc-collected at Pagy::I18n.load time.
+
# utility variables
zero_one = ['zero', 'one'].freeze
from2to4 = (2..4).freeze
@@ -9,10 +11,10 @@
from11to14 = (11..14).freeze
from12to14 = (12..14).freeze
-# Plurals
-# A plural proc returns a plural type string based on the passed count
-# Each plural proc may apply to one or more languages below
-plurals = {
+# Pluralization (p11n)
+# A pluralization proc returns a plural type string based on the passed count
+# Each proc may apply to one or more locales below
+p11n = {
zero_one_other: lambda {|count| zero_one[count] || 'other'},
zero_one_few_many_other: lambda do |count|
@@ -36,14 +38,13 @@
end
}
-# Languages (language/plural pairs)
-# Contain all the entries for all the languages defined in the dictionaries.
-# The default plural for languages not explicitly listed here
-# is the :zero_one_other plural (used for English)
-Hash.new(plurals[:zero_one_other]).tap do |languages|
- languages['en'] = plurals[:zero_one_other]
- languages['ru'] = plurals[:zero_one_few_many_other]
- languages['pl'] = plurals[:pl]
+# Hash of locale/pluralization pairs
+# Contain all the entries for all the locales defined as dictionaries.
+# The default pluralization for locales not explicitly listed here
+# is the :zero_one_other pluralization proc (used for English)
+Hash.new(p11n[:zero_one_other]).tap do |hash|
+ hash['ru'] = p11n[:zero_one_few_many_other]
+ hash['pl'] = p11n[:pl]
end
-# PR for other languages and plurals are very welcome. Thanks!
+# PR for other locales and pluralizations are very welcome. Thanks!
diff --git a/lib/pagy/extras/i18n.rb b/lib/pagy/extras/i18n.rb
index a8b487964..48d2ce759 100644
--- a/lib/pagy/extras/i18n.rb
+++ b/lib/pagy/extras/i18n.rb
@@ -1,4 +1,5 @@
# See the Pagy documentation: https://ddnexus.github.io/pagy/extras/i18n
+# frozen_string_literal: true
class Pagy
# Use ::I18n gem
@@ -6,10 +7,11 @@ module Frontend
::I18n.load_path += Dir[Pagy.root.join('locales', '*.yml')]
- # Override the built-in pagy_t
- def pagy_t(*args)
- ::I18n.t(*args)
- end
+ Pagy::I18n.clear.instance_eval { undef :load; undef :t } # unload the pagy default constant for efficiency
+
+ # no :pagy_without_i18n alias with the i18n gem
+ def pagy_t_with_i18n(*args) ::I18n.t(*args) end
+ alias :pagy_t :pagy_t_with_i18n
end
end
diff --git a/lib/pagy/frontend.rb b/lib/pagy/frontend.rb
index ff52d3d21..f1a8b5c14 100644
--- a/lib/pagy/frontend.rb
+++ b/lib/pagy/frontend.rb
@@ -5,6 +5,10 @@
class Pagy
+ # I18n static hash loaded at startup, used as default alternative to the i18n gem.
+ # see https://ddnexus.github.io/pagy/api/frontend#i18n
+ I18n = eval(Pagy.root.join('locales', 'utils', 'i18n.rb').read) #rubocop:disable Security/Eval
+
# All the code here has been optimized for performance: it may not look very pretty
# (as most code dealing with many long strings), but its performance makes it very sexy! ;)
module Frontend
@@ -57,25 +61,8 @@ def pagy_link_proc(pagy, link_extra='')
else '' end } #{extra}>#{text}" }
end
- # Pagy::Frontend::I18N
- def (I18N = {data:{}}).load(file:Pagy.root.join('locales', 'en.yml'), language: 'en')
- self[:data] = YAML.load_file(file)[language]
- self[:plural] = eval(Pagy.root.join('locales', 'plurals.rb').read)[language] #rubocop:disable Security/Eval
- end; I18N.load
-
- # Similar to I18n.t for streamlined interpolation and pluralization but without dynamic translation.
- # It is specialized for Pagy and 5x faster than I18n.t (see https://ddnexus.github.io/pagy/api/frontend#i18n)
- # See also https://ddnexus.github.io/pagy/extras/i18n if you need to use the standard I18n gem instead
- def pagy_t(path, vars={})
- value = I18N[:data].dig(*path.split('.')) or return %(translation missing: "#{path}")
- if value.is_a?(Hash)
- vars.key?(:count) or return value
- plural = I18N[:plural].call(vars[:count])
- value.key?(plural) or return %(invalid pluralization data: "#{path}" cannot be used with count: #{vars[:count]}; key "#{plural}" is missing.)
- value = value[plural] or return %(translation missing: "#{path}")
- end
- sprintf value, Hash.new{|_,k| "%{#{k}}"}.merge!(vars) # interpolation
- end
+ # Similar to I18n.t: just ~12x faster using ~6x less memory
+ def pagy_t(path, vars={}) Pagy::I18n.t(@pagy_locale, path, vars) end
end
end
diff --git a/test/pagy/custom.yml b/test/pagy/custom.yml
new file mode 100644
index 000000000..b05f194cb
--- /dev/null
+++ b/test/pagy/custom.yml
@@ -0,0 +1,20 @@
+custom:
+ pagy:
+ nav:
+ prev: "‹ Custom Prev" # test
+ next: "Next ›"
+ gap: "…"
+ info:
+ single_page:
+ zero: "No %{item_name} found"
+ one: "Displaying 1 %{item_name}"
+ other: "Displaying all %{count} %{item_name}"
+ multiple_pages: "Displaying %{item_name} %{from}-%{to} of %{count} in total"
+ item_name:
+ zero: "items"
+ one: "item"
+ other: "items"
+ compact: "Page %{page_input} of %{pages}"
+ items:
+ one: "Show %{items_input} item per page"
+ other: "Show %{items_input} items per page"
diff --git a/test/pagy/extras/i18n_test.rb b/test/pagy/extras/i18n_test.rb
index d641c9d3e..a60f19898 100644
--- a/test/pagy/extras/i18n_test.rb
+++ b/test/pagy/extras/i18n_test.rb
@@ -10,11 +10,6 @@
describe "#pagy_t with I18n" do
- it 'fetches data' do
- Pagy::Frontend::I18N[:data]['pagy']['nav']['prev'].must_equal "‹ Prev"
- Pagy::Frontend::I18N[:data]['pagy']['nav']['gap'].must_equal "…"
- end
-
it 'pluralizes' do
frontend.pagy_t('pagy.nav.prev').must_equal "‹ Prev"
frontend.pagy_t('pagy.info.item_name', count: 0).must_equal 'items'
diff --git a/test/pagy/frontend_test.rb b/test/pagy/frontend_test.rb
index 2bf069282..dfbd931cf 100644
--- a/test/pagy/frontend_test.rb
+++ b/test/pagy/frontend_test.rb
@@ -99,17 +99,11 @@
describe "#pagy_t" do
- it 'fetches I18N data' do
- Pagy::Frontend::I18N[:data]['pagy']['nav']['prev'].must_equal "‹ Prev"
- Pagy::Frontend::I18N[:data]['pagy']['nav']['gap'].must_equal "…"
- end
-
it 'pluralizes' do
frontend.pagy_t('pagy.nav.prev').must_equal "‹ Prev"
frontend.pagy_t('pagy.info.item_name', count: 0).must_equal "items"
frontend.pagy_t('pagy.info.item_name', count: 1).must_equal "item"
frontend.pagy_t('pagy.info.item_name', count: 10).must_equal "items"
-
end
it 'interpolates' do
@@ -117,10 +111,46 @@
frontend.pagy_t('pagy.info.single_page', count: 1).must_equal "Displaying 1 %{item_name}"
frontend.pagy_t('pagy.info.single_page', count: 10).must_equal "Displaying all 10 %{item_name}"
frontend.pagy_t('pagy.info.multiple_pages', count: 10).must_equal "Displaying %{item_name} %{from}-%{to} of 10 in total"
+ frontend.pagy_t('pagy.info.multiple_pages', item_name: 'Products', count: 300, from: 101, to: 125).must_equal "Displaying Products 101-125 of 300 in total"
end
it 'handles missing paths' do
- frontend.pagy_t('pagy.nav.not_here').must_equal 'translation missing: "pagy.nav.not_here"'
+ frontend.pagy_t('pagy.nav.not_here').must_equal '[translation missing: "pagy.nav.not_here"]'
+ frontend.pagy_t('pagy.nav.gap.not_here').must_equal '[translation missing: "pagy.nav.gap.not_here"]'
+ end
+
+
+ end
+
+ describe "Pagy::I18n" do
+
+ it 'loads custom :locale, :filepath and :pluralize' do
+ proc{ Pagy::I18n.load(locale: 'xx') }.must_raise Errno::ENOENT
+ proc{ Pagy::I18n.load(locale: 'xx', filepath: Pagy.root.join('locales', 'en.yml'))}.must_raise ArgumentError
+ proc{ Pagy::I18n.load(locale: 'en', filepath: Pagy.root.join('locales', 'xx.yml')) }.must_raise Errno::ENOENT
+ custom_dictionary = File.join(File.dirname(__FILE__), 'custom.yml')
+ Pagy::I18n.load(locale: 'custom', filepath: custom_dictionary)
+ Pagy::I18n.t('custom', 'pagy.nav.prev').must_equal "‹ Custom Prev"
+ Pagy::I18n.load(locale: 'en', pluralize: lambda{|_| 'one' }) # returns always 'one' regardless the count
+ Pagy::I18n.t(nil, 'pagy.info.item_name', count: 0).must_equal "item"
+ Pagy::I18n.t('en', 'pagy.info.item_name', count: 0).must_equal "item"
+ Pagy::I18n.t('en', 'pagy.info.item_name', count: 1).must_equal "item"
+ Pagy::I18n.t('en', 'pagy.info.item_name', count: 10).must_equal "item"
+ Pagy::I18n.load(locale: 'en') # reset for other tests
+ end
+
+ it 'switches :locale according to @pagy_locale' do
+ Pagy::I18n.load({locale: 'de'}, {locale: 'en'}, {locale: 'nl'})
+ frontend.instance_variable_set(:'@pagy_locale', 'nl')
+ frontend.pagy_t('pagy.info.item_name', count: 1).must_equal "stuk"
+ frontend.instance_variable_set(:'@pagy_locale', 'en')
+ frontend.pagy_t('pagy.info.item_name', count: 1).must_equal "item"
+ frontend.instance_variable_set(:'@pagy_locale', nil)
+ frontend.pagy_t('pagy.info.item_name', count: 1).must_equal "Eintrag"
+ frontend.instance_variable_set(:'@pagy_locale', 'unknown')
+ frontend.pagy_t('pagy.info.item_name', count: 1).must_equal "Eintrag" # silently serves the first loaded locale
+ Pagy::I18n.load(locale: 'en') # reset for other tests
+ frontend.instance_variable_set(:'@pagy_locale', nil) # reset for other tests
end
end
@@ -135,13 +165,14 @@
end
it 'renders with existing i18n path' do
- Pagy::Frontend::I18N[:data]['pagy']['info']['product'] = { 'zero' => 'Products',
- 'one' => 'Product',
- 'other' => 'Products' }
+ Pagy::I18n['en'][0]['pagy.info.product.zero'] = lambda{|_| 'Products'}
+ Pagy::I18n['en'][0]['pagy.info.product.one'] = lambda{|_| 'Product'}
+ Pagy::I18n['en'][0]['pagy.info.product.other'] = lambda{|_| 'Products'}
frontend.pagy_info(Pagy.new count: 0, item_path: 'pagy.info.product').must_equal "No Products found"
frontend.pagy_info(Pagy.new count: 1, item_path: 'pagy.info.product').must_equal "Displaying 1 Product"
frontend.pagy_info(Pagy.new count: 13, item_path: 'pagy.info.product').must_equal "Displaying all 13 Products"
frontend.pagy_info(Pagy.new count: 100, item_path: 'pagy.info.product', page: 3).must_equal "Displaying Products 41-60 of 100 in total"
+ Pagy::I18n.load(locale: 'en') # reset for other tests
end
end