Skip to content

Commit

Permalink
refactoring of i18n:
Browse files Browse the repository at this point in the history
- I18n gem compliant (removed plural keys inconsistent with the locale)
- added tests for all the pluralization procs
- simplified and normalized Pagy dictionary file
- renamed :items_Path to :colletion_key
- added :collection_key lookup for the items_selector_js helper
  • Loading branch information
ddnexus committed Apr 28, 2019
1 parent 8ebb1ab commit 260e7d4
Show file tree
Hide file tree
Showing 46 changed files with 575 additions and 349 deletions.
4 changes: 2 additions & 2 deletions docs/api/backend.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ If you need to use multiple different types of collections in the same app or ac

Sub-method called only by the `pagy` method, it returns the hash of variables used to initialize the Pagy object.

Override it if you need to add or change some variable. For example you may want to add the `:item_path` or the `:item_name` to customize the `pagy_info` output, or even cache the `count`.
Override it if you need to add or change some variable. For example you may want to add the `:i18n_key` in order to customize output _(see [Customizing the item name](../how-to.md#customizing-the-item-name))_, or even cache the `count`.

_IMPORTANT_: `:count` and `:page` are the only 2 required Pagy core variables, so be careful not to remove them from the returned hash.

See also the [How To](../how-to.md) wiki page for some usage example.
See also the [How To](../how-to.md) page for some usage example.

### pagy_get_items(collection, pagy)

Expand Down
26 changes: 12 additions & 14 deletions docs/api/frontend.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,13 @@ This method provides the info about the content of the current pagination. For e

Will produce something like:

```HTML
Displaying items <b>476-500</b> of <b>1000</b> in total
```

Or, if you provide the `:item_path` variable for the Product model, it will produce a model-specific output like:
or, if you use the `:i18n_key` variable a custom/collection-specific output:

```HTML
Displaying Products <b>476-500</b> of <b>1000</b> in total
```

See also [Using the pagy_info helper](../how-to.md#using-the-pagy_info-helper).
_(see [Customizing the item name](../how-to.md#customizing-the-item-name))_

### pagy_url_for(page, pagy)

Expand Down Expand Up @@ -164,13 +160,15 @@ Pagy is i18n ready. That means that all its strings are stored in the dictionary

**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.

Pagy can consume i18n using its own recommended [internal implementation](#pagy-i18n-implementation) or using the [standard I18n gem](#using-the-standard-i18n-gem)

### Pagy I18n implementation

The pagy internal i18n implementation is ~18x faster and uses ~10x less memory than the standard `i18n` gem.

Since Pagy version 2.0, you can use it for both single-language and multi-language apps. If (the rest of) your app is using i18n, it will work independently from the pagy i18n.
Since Pagy version 2.0, you can use it for both single-language and multi-language apps. If (the rest of) your app is using i18n, it will continue to work independently from the pagy i18n.

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.
The pagy internal i18n is implemented around the `Pagy::I18n` constant. You may need to configure it in the [pagy.rb](https://github.com/ddnexus/pagy/blob/master/lib/config/pagy.rb) initializer.

#### Pagy::I18n.load configuration

Expand Down Expand Up @@ -206,9 +204,9 @@ Pagy::I18n.load({locale: 'en'},
```

**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).
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 `'one'` or `'other'`, depending on the passed count).

#### Set the request locale in multi-language apps
#### Setting the request locale in multi-language apps

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:

Expand All @@ -235,17 +233,17 @@ en:
activerecord:
models:
product:
zero: Products
one: Product
other: Products
...
```
_(See also the [pagy_info method](#pagy_infopagy))_
_(See also the [pagy_info method](#pagy_infopagy) and [Customizing the item name](../how-to.md#customizing-the-item-name))_
### Using the standard I18n gem
### Using the I18n gem
If 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.
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.
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.
18 changes: 9 additions & 9 deletions docs/api/pagy.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,15 @@ They are all integers:

### Other Variables

| Variable | Description | Default |
|:--------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------|
| `:size` | the size of the page links to show: array of initial pages, before current page, after current page, final pages. _(see also [Control the page links](../how-to.md#controlling-the-page-links))_ | `[1,4,4,1]` |
| `:page_param` | the name of the page param name used in the url. _(see [Customizing the page param](../how-to.md#customizing-the-page-param))_ | `:page` |
| `:params` | the arbitrary param hash to add to the url. _(see [Customizing the params](../how-to.md#customizing-the-params))_ | `{}` |
| `:anchor` | the arbitrary anchor string (including the "#") to add to the url. _(see [Customizing the params](../how-to.md#customizing-the-params))_ | `""` |
| `:link_extra` | the extra attributes string (formatted as a valid HTML attribute/value pairs) added to the page links _(see [Customizing the link attributes](../how-to.md#customizing-the-link-attributes))_ | `""` |
| `:item_path` | the dictionary path used by the `pagy_info` method to lookup the item/model name _(see [Using the pagy info helper](../how-to.md#using-the-pagy_info-helper))_ | `""` |
| `:cycle` | enable cycling/circular/infinite pagination: `true` sets `next` to `1` when the current page is the last page | `false` |
| Variable | Description | Default |
|:------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------|
| `:size` | the size of the page links to show: array of initial pages, before current page, after current page, final pages. _(see also [Control the page links](../how-to.md#controlling-the-page-links))_ | `[1,4,4,1]` |
| `:page_param` | the name of the page param name used in the url. _(see [Customizing the page param](../how-to.md#customizing-the-page-param))_ | `:page` |
| `:params` | the arbitrary param hash to add to the url. _(see [Customizing the params](../how-to.md#customizing-the-params))_ | `{}` |
| `:anchor` | the arbitrary anchor string (including the "#") to add to the url. _(see [Customizing the params](../how-to.md#customizing-the-params))_ | `""` |
| `:link_extra` | the extra attributes string (formatted as a valid HTML attribute/value pairs) added to the page links _(see [Customizing the link attributes](../how-to.md#customizing-the-link-attributes))_ | `""` |
| `:i18n_key` | the i18n key to lookup the `item_name` that gets interpolated in a few helper outputs _(see [Customizing the item name](../how-to.md#customizing-the-item-name))_ | `"pagy.item_name"` |
| `:cycle` | enable cycling/circular/infinite pagination: `true` sets `next` to `1` when the current page is the last page | `false` |

There is no specific validation for non-instance variables.

Expand Down
13 changes: 11 additions & 2 deletions docs/extras/items.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,21 @@ This extra overrides the `pagy_countless_get_vars` method of the `Pagy::Backend`

This extra overrides also the `pagy_url_for` method of the `Pagy::Frontend` module in order to add the `:items_param` param to the url of the links.

### pagy_items_selector_js(pagy)
### pagy_items_selector_js(pagy, ...)

This helper provides an items selector UI, which allows the user to select any arbitrary number of items per page (below the `:max_items` number) in a numeric input field. It looks like:

<span>Show <input type="number" min="1" max="100" value="20" style="padding: 0; text-align: center; width: 3rem;"> items per page</span>

You can change/translate its text by editing the `pagy.items` value in the [dictionaray files](https://github.com/ddnexus/pagy/blob/master/lib/locales).
or, if you use the `:i18n_key` variable you can get a custom/collection-specific output:

<span>Show <input type="number" min="1" max="100" value="20" style="padding: 0; text-align: center; width: 3rem;"> Products per page</span>

_(see [Customizing the item name](../how-to.md#customizing-the-item-name))_

When the items number is changed with the selector, pagy will reload the pagination UI using the selected items per page. It will also request the _right_ page number calculated in order to contain the first item of the previously displayed page. That way the new displayed page will roughly show the same items in the collection before the items change.

This method can take an extra `id` argument, which is used to build the `id` attribute of the `nav` tag. Since the internal automatic id generation is based on the code line where you use the helper, you _must_ pass an explicit id if you are going to use more than one `*_js` call in the same line for the same file.

**Notice**: passing an explicit id is also a bit faster than having pagy to generate one.

4 changes: 2 additions & 2 deletions docs/extras/navs.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ Here is what you should consider/ensure:

Similar to the `pagy_nav` helper, but faster and rendered on the client side, with added responsiveness.

It can take an extra `id` argument, which is used to build the `id` attribute of the `nav` tag. Since the internal automatic id generation is based on the code line where you use the helper, you _must_ pass an explicit id if you are going to use more than one `pagy*_nav_js` or `pagy*_combo_nav_js` call in the same line for the same file.
It can take an extra `id` argument, which is used to build the `id` attribute of the `nav` tag. Since the internal automatic id generation is based on the code line where you use the helper, you _must_ pass an explicit id if you are going to use more than one `*_js` call in the same line for the same file.

**Notice**: passing an explicit id is also a bit faster than having pagy to generate one.

Expand Down Expand Up @@ -145,6 +145,6 @@ Other extras provide also the following framework-styled helpers:

Renders a javascript-powered compact navigation helper.

It can take an extra `id` argument, which is used to build the `id` attribute of the `nav` tag. Since the internal automatic id generation is based on the code line where you use the helper, you _must_ pass an explicit id if you are going to use more than one `pagy*_nav_js` or `pagy*_combo_nav_js` call in the same line for the same page.
It can take an extra `id` argument, which is used to build the `id` attribute of the `nav` tag. Since the internal automatic id generation is based on the code line where you use the helper, you _must_ pass an explicit id if you are going to use more than one `*_js` call in the same line for the same page.

**Notice**: passing an explicit id is also a bit faster than having pagy to generate one.
59 changes: 28 additions & 31 deletions docs/how-to.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,34 @@ end

That would produce links that look like e.g. `<a href="2">2</a>`. Then you can attach a javascript "click" event on the page links. When triggered, the `href` content (i.e. the page number) should get copied to a hidden `"page"` input and the form should be posted.

## Customizing the item name

The `pagy_info` and the `pagy_items_selector_js` helpers use the "item"/"items" generic name in their output. You can change that by editing the values of the `"pagy.item_name"` i18n key in the [dictionaray files](https://github.com/ddnexus/pagy/blob/master/lib/locales) that your app is using.

Besides you can also (dynamically) set the `:i18n_key` variable to let Pagy know where to lookup the item name in some dictionary file (instead looking it up in the default `"pagy.item_name"` key).

You have a few ways to do that:

1. you can override the `pagy_get_vars` method in your controller, adding the dynamically set `:i18n_key`. For example with ActiveRecord (mostly useful with the [i18n extra](extras/i18n.md) or if you copy over the AR keys into the pagy dictionary):
```ruby
def pagy_get_vars(collection, vars)
{ count: ...,
page: ...,
i18n_key: "activerecord.models.#{collection.model_name.i18n_key}" }.merge!(vars)
end
```

2. you can set the `:i18n_key` variable, either globally using the `Pagy::VARS` hash or per instance with the `Pagy.new` method or with the `pagy` controller method:
```ruby
# all the Pagy instances will have the default
Pagy::VARS[:i18n_key] = 'activerecord.models.product'
# or single Pagy instance
@pagy, @record = pagy(my_scope, i18n_key: 'activerecord.models.product' )
```

**Notice**: The variables passed to a Pagy object have the precedence over the variables returned by the `pagy_get_vars`. The fastest way is passing a literal string to the `pagy` method, the most convenient way is using `pagy_get_vars`.

## Paginate an Array

Please, use the [array](extras/array.md) extra.
Expand Down Expand Up @@ -429,37 +457,6 @@ When the count caching is not an option, you may want to use the [countless extr

Pagy implements the [RFC-8288](https://tools.ietf.org/html/rfc8288) compliant http response headers (and other helpers) useful for API pagination: no need to use other dependencies. See the [headers extra](http://ddnexus.github.io/pagy/extras/headers) documentation and examples.

## Using the pagy_info helper

The page info that you get by using the `pagy_info` helper (e.g. "Displaying items __476-500__ of __1000__ in total") is composed by 2 strings stored in the `pagy.yml` locale file:

- the text of the sentence: located at the i18n paths `"pagy.info.single_page"` and `"pagy.info.multiple_pages"` (depending on how many pages compose the pagination)
- the generic item/model name: located at the i18n path`"pagy.info.item_name"`

While the text part can be always static, you may want the item/model name to be the actual model name, i.e. not just "items" but actually something like "Products" or something specific.

You can do so by setting the `:item_path` variable to the path to lookup in the dictionary file, in one of the following 2 ways:

1. by overriding the `pagy_get_vars` method in your controller (valid for all the Pagy instances) adding the `:item_path`. For example (with ActiveRecord):
```ruby
def pagy_get_vars(collection, vars)
{ count: collection.count(:all),
page: params[vars[:page_param]||Pagy::VARS[:page_param]],
item_path: "activerecord.models.#{collection.model_name.i18n_key}" }.merge!(vars)
end
```

2. by passing the variable to the Pagy object, either using the `Pagy::VARS` hash or `Pagy.new` method or `pagy` controller method:
```ruby
# all the Pagy instances will have the default
Pagy::VARS[:item_path] = 'activerecord.models.product'
# or single Pagy instance
@pagy, @record = pagy(my_scope, item_path: 'activerecord.models.product' )
```

**Notice**: The variables passed to a Pagy object have the precedence over the variables returned by the `pagy_get_vars`. The fastest way is passing a literal string to the `pagy` method, the most convenient way is using `pagy_get_vars`.

## Maximizing Performance

Here are some tips that will help chosing the best way to use Pagy, depending on your requirements and environment.
Expand Down
4 changes: 3 additions & 1 deletion lib/config/pagy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@
# Pagy::VARS[:params] = {} # default
# Pagy::VARS[:anchor] = '#anchor' # example
# Pagy::VARS[:link_extra] = 'data-remote="true"' # example
# Pagy::VARS[:item_path] = 'activerecord.models.product' # example


# Rails
Expand Down Expand Up @@ -154,3 +153,6 @@
# than the default pagy internal i18n (see above)
# See https://ddnexus.github.io/pagy/extras/i18n
# require 'pagy/extras/i18n'

# Default i18n key
# Pagy::VARS[:i18n_key] = 'pagy.item_name' # default
Loading

0 comments on commit 260e7d4

Please sign in to comment.