diff --git a/README.md b/README.md index c10b192e3..1a7ac9363 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ The accessibility column indicates whether the functionality is accessible in it | [tooltip](https://lion-web-components.netlify.app/?path=/docs/overlays-tooltip--main) | [![tooltip](https://img.shields.io/npm/v/@lion/tooltip.svg)](https://www.npmjs.com/package/@lion/tooltip) | Tooltip element | [#175][i175] | | **-- [Navigation System](https://lion-web-components.netlify.app/?path=/docs/navigation-intro--page) --** | | Components which are used to guide users | | | [accordion](https://lion-web-components.netlify.app/?path=/docs/navigation-accordion--main) | [![accordion](https://img.shields.io/npm/v/@lion/accordion.svg)](https://www.npmjs.com/package/@lion/accordion) | Accordion | ✔️ | +| [pagination](https://lion-web-components.netlify.app/?path=/docs/navigation-pagination--main) | [![pagination](https://img.shields.io/npm/v/@lion/pagination.svg)](https://www.npmjs.com/package/@lion/pagination) | Pagination | ✔️ | | [steps](https://lion-web-components.netlify.app/?path=/docs/navigation-steps--main) | [![steps](https://img.shields.io/npm/v/@lion/steps.svg)](https://www.npmjs.com/package/@lion/steps) | Multi Step System | n/a | | [tabs](https://lion-web-components.netlify.app/?path=/docs/navigation-tabs--main) | [![tBS](https://img.shields.io/npm/v/@lion/tabs.svg)](https://www.npmjs.com/package/@lion/tabs) | Move between a small number of equally important views | n/a | | **-- [localize System](https://lion-web-components.netlify.app/?path=/docs/localize-intro--page) --** | | Localize text, numbers, dates and a way to store/fetch these data. | | @@ -77,7 +78,7 @@ The accessibility column indicates whether the functionality is accessible in it | [core](https://lion-web-components.netlify.app/?path=/docs/others-system-core--page) | [![core](https://img.shields.io/npm/v/@lion/core.svg)](https://www.npmjs.com/package/@lion/core) | Core System (exports LitElement, lit-html) | n/a | | [ajax](https://lion-web-components.netlify.app/?path=/docs/others-ajax--performing-get-requests) | [![ajax](https://img.shields.io/npm/v/@lion/ajax.svg)](https://www.npmjs.com/package/@lion/ajax) | Fetching data via ajax request | n/a | | [calendar](https://lion-web-components.netlify.app/?path=/docs/others-calendar--main) | [![calendar](https://img.shields.io/npm/v/@lion/calendar.svg)](https://www.npmjs.com/package/@lion/calendar) | Standalone calendar | [#195][i195], [#194][i194] | -| [collapsible](https://lion-web-components.netlify.app/?path=/docs/others-collapsible--main) | [![collapsible](https://img.shields.io/npm/v/@lion/collapsible.svg)](https://www.npmjs.com/package/@lion/collapsible) | Combination of a button and a chunk of extra content | | +| [collapsible](https://lion-web-components.netlify.app/?path=/docs/others-collapsible--main) | [![collapsible](https://img.shields.io/npm/v/@lion/collapsible.svg)](https://www.npmjs.com/package/@lion/collapsible) | Combination of a button and a chunk of extra content | ✔️ | | **-- [Helpers](https://lion-web-components.netlify.app/?path=/docs/helpers-intro--page) --** | [![helpers](https://img.shields.io/npm/v/@lion/helpers.svg)](https://www.npmjs.com/package/@lion/helpers) | Helpers to make your and your life easier | | | [sb-action-logger](https://lion-web-components.netlify.app/?path=/docs/helpers-storybook-action-logger--main) | | Storybook action logger | diff --git a/docs/intros/intros-navigation.md b/docs/intros/intros-navigation.md index c221c9576..d2e9d8acb 100644 --- a/docs/intros/intros-navigation.md +++ b/docs/intros/intros-navigation.md @@ -8,10 +8,12 @@ Navigational elements are used to guide users within your page. ## Packages -| Package | Version | Description | -| ---------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | -| [steps](?path=/docs/navigation-steps--default-story) | [![steps](https://img.shields.io/npm/v/@lion/steps.svg)](https://www.npmjs.com/package/@lion/steps) | Multi Step System | -| [tabs](?path=/docs/navigation-tabs--default-story) | [![tBS](https://img.shields.io/npm/v/@lion/tabs.svg)](https://www.npmjs.com/package/@lion/tabs) | Move between a small number of equally important views | +| Package | Version | Description | +| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------- | +| [accordion](?path=/docs/accordion-steps--default-story) | [![accordion](https://img.shields.io/npm/v/@lion/accordion.svg)](https://www.npmjs.com/package/@lion/accordion) | A component to toggle the display of sections of content | +| [pagination](?path=/docs/pagination-steps--default-story) | [![pagination](https://img.shields.io/npm/v/@lion/pagination.svg)](https://www.npmjs.com/package/@lion/pagination) | A component that handles pagination | +| [steps](?path=/docs/navigation-steps--default-story) | [![steps](https://img.shields.io/npm/v/@lion/steps.svg)](https://www.npmjs.com/package/@lion/steps) | Multi Step System | +| [tabs](?path=/docs/navigation-tabs--default-story) | [![tBS](https://img.shields.io/npm/v/@lion/tabs.svg)](https://www.npmjs.com/package/@lion/tabs) | Move between a small number of equally important views | ```js script export default { diff --git a/packages/pagination/CHANGELOG.md b/packages/pagination/CHANGELOG.md new file mode 100644 index 000000000..420e6f23d --- /dev/null +++ b/packages/pagination/CHANGELOG.md @@ -0,0 +1 @@ +# Change Log diff --git a/packages/pagination/README.md b/packages/pagination/README.md new file mode 100644 index 000000000..46bd9b61e --- /dev/null +++ b/packages/pagination/README.md @@ -0,0 +1,145 @@ +# Pagination + +`lion-pagination` component that handles pagination. + +```js script +import { html } from 'lit-html'; + +import './lion-pagination.js'; + +export default { + title: 'Navigation/Pagination', +}; +``` + +```js preview-story +export const main = () => html` `; +``` + +## Features + +- You can pass the total number of pages in the `count` parameter, and the current page in the `current` parameter. If `current` is not defined it will default to the value 1. +- On a click or parameter change of `current` it will fire an event back called `current-changed`. + +## How to use + +### Installation + +```bash +npm i --save @lion/pagination +``` + +```js +import { LionPagination } from '@lion/pagination'; +// or +import '@lion/pagination/lion-pagination.js'; +``` + +### Usage + +```html + +``` + +### Examples + +### Without current defined + +```js preview-story +export const withoutCurrentPage = () => { + return html` `; +}; +``` + +### Ensure a count value + +Be sure to set a count value or you will get an "empty" pagination. + +```js preview-story +export const ensureCount = () => { + return html` `; +}; +``` + +#### Methods + +There are the following methods available to control the pagination. + +- `next()`: move forward in pagination +- `previous()`: goes back to pagination +- `first()`: to the first page +- `last()`: to the last page +- `goto(pageNumber)`: to the specific page + +```js preview-story +export const methods = () => { + setTimeout(() => { + document.getElementById('pagination-method-demo').innerText = document.getElementById( + 'pagination-method', + ).current; + }); + + return html` +

The current page is:

+ { + const paginationState = document.getElementById('pagination-method-demo'); + paginationState.innerText = e.target.current; + }} + > +
+ + +
+
+ + +
+
+ +
+ `; +}; +``` + +#### Event + +`lion-pagination` fires an event on button click to notify the component's current state. It is useful for analytics purposes or to perform some actions on page change. + +- `@current-changed`: triggers when the current page is changed + +```js preview-story +export const event = () => { + setTimeout(() => { + document.getElementById('pagination-event-demo-text').innerText = document.getElementById( + 'pagination-event-demo', + ).current; + }); + + return html` +

The current page is:

+ { + const paginationState = document.getElementById('pagination-event-demo-text'); + paginationState.innerText = e.target.current; + }} + > + `; +}; +``` diff --git a/packages/pagination/index.js b/packages/pagination/index.js new file mode 100644 index 000000000..279660b2b --- /dev/null +++ b/packages/pagination/index.js @@ -0,0 +1 @@ +export { LionPagination } from './src/LionPagination.js'; diff --git a/packages/pagination/lion-pagination.js b/packages/pagination/lion-pagination.js new file mode 100644 index 000000000..bad17b764 --- /dev/null +++ b/packages/pagination/lion-pagination.js @@ -0,0 +1,3 @@ +import { LionPagination } from './src/LionPagination.js'; + +customElements.define('lion-pagination', LionPagination); diff --git a/packages/pagination/package.json b/packages/pagination/package.json new file mode 100644 index 000000000..bcf67f2bc --- /dev/null +++ b/packages/pagination/package.json @@ -0,0 +1,46 @@ +{ + "name": "@lion/pagination", + "version": "0.0.0", + "description": "A component that handles pagination.", + "license": "MIT", + "author": "ing-bank", + "homepage": "https://github.com/ing-bank/lion/", + "repository": { + "type": "git", + "url": "https://github.com/ing-bank/lion.git", + "directory": "packages/pagination" + }, + "main": "index.js", + "module": "index.js", + "files": [ + "*.d.ts", + "*.js", + "docs", + "src", + "test", + "test-helpers", + "translations", + "types" + ], + "scripts": { + "prepublishOnly": "../../scripts/npm-prepublish.js", + "start": "cd ../../ && yarn dev-server --open packages/pagination/README.md", + "test": "cd ../../ && yarn test:browser --grep \"packages/pagination/test/**/*.test.js\"", + "test:watch": "cd ../../ && yarn test:browser:watch --grep \"packages/pagination/test/**/*.test.js\"" + }, + "sideEffects": [ + "lion-pagination.js" + ], + "dependencies": { + "@lion/core": "0.10.0", + "@lion/localize": "0.14.2" + }, + "keywords": [ + "lion", + "pagination", + "web-components" + ], + "publishConfig": { + "access": "public" + } +} diff --git a/packages/pagination/src/LionPagination.js b/packages/pagination/src/LionPagination.js new file mode 100644 index 000000000..8afbaae00 --- /dev/null +++ b/packages/pagination/src/LionPagination.js @@ -0,0 +1,296 @@ +import { LitElement, html, css } from '@lion/core'; +import { LocalizeMixin } from '@lion/localize'; +/** + * `LionPagination` is a class for custom Pagination element (`` web component). + * + * @customElement lion-pagination + * @extends LitElement + */ +export class LionPagination extends LocalizeMixin(LitElement) { + static get styles() { + return css` + :host { + cursor: default; + } + + ul { + list-style: none; + padding: 0; + text-align: center; + } + + li { + display: inline-block; + } + + button[aria-current='true'] { + font-weight: bold; + } + `; + } + + static get localizeNamespaces() { + return [ + { + 'lion-pagination': locale => { + switch (locale) { + case 'bg-BG': + return import('../translations/bg.js'); + case 'cs-CZ': + return import('../translations/cs.js'); + case 'de-AT': + case 'de-DE': + return import('../translations/de.js'); + case 'en-AU': + case 'en-GB': + case 'en-PH': + case 'en-US': + return import('../translations/en.js'); + case 'es-ES': + return import('../translations/es.js'); + case 'fr-FR': + case 'fr-BE': + return import('../translations/fr.js'); + case 'hu-HU': + return import('../translations/hu.js'); + case 'it-IT': + return import('../translations/it.js'); + case 'nl-BE': + case 'nl-NL': + return import('../translations/nl.js'); + case 'pl-PL': + return import('../translations/pl.js'); + case 'ro-RO': + return import('../translations/ro.js'); + case 'ru-RU': + return import('../translations/ru.js'); + case 'sk-SK': + return import('../translations/sk.js'); + case 'uk-UA': + return import('../translations/uk.js'); + case 'zh-CN': + return import('../translations/zh.js'); + default: + return import('../translations/en.js'); + } + }, + }, + ...super.localizeNamespaces, + ]; + } + + static get properties() { + return { + current: { + type: Number, + reflect: true, + }, + count: { + type: Number, + reflect: true, + }, + }; + } + + set current(value) { + if (value !== this.current) { + const oldValue = this.current; + this.__current = value; + this.dispatchEvent(new Event('current-changed')); + this.requestUpdate('current', oldValue); + } + } + + get current() { + return this.__current; + } + + constructor() { + super(); + this.__visiblePages = 5; + this.current = 1; + this.count = 0; + } + + /** + * Go next in pagination + * @public + */ + next() { + if (this.current < this.count) { + this.__fire(this.current + 1); + } + } + + /** + * Go to first page + * @public + */ + first() { + if (this.count >= 1) { + this.__fire(1); + } + } + + /** + * Go to the last page + * @public + */ + last() { + if (this.count >= 1) { + this.__fire(this.count); + } + } + + /** + * Go to the specific page + * @public + */ + goto(pageNumber) { + if (pageNumber >= 1 && pageNumber <= this.count) { + this.__fire(pageNumber); + } + } + + /** + * Go back in pagination + * @public + */ + previous() { + if (this.current !== 1) { + this.__fire(this.current - 1); + } + } + + /** + * Set desired page in the pagination and fire the current changed event. + * @param {Number} page page number to be set + * @private + */ + __fire(page) { + if (page !== this.current) { + this.current = page; + } + } + + /** + * Calculate nav list based on current page selection. + * @returns {Array} + * @private + */ + __calculateNavList() { + const start = 1; + const finish = this.count; + // If there are more pages then we want to display we have to redo the list each time + // Else we can just return the same list every time. + if (this.count > this.__visiblePages) { + // Calculate left side of current page and right side + const pos3 = this.current - 1; + const pos4 = this.current; + const pos5 = this.current + 1; + // if pos 3 is lower than 4 we have a predefined list of elements + if (pos4 <= 4) { + const list = Array(this.__visiblePages) + .fill() + .map((_, idx) => start + idx); + list.push('...'); + list.push(this.count); + return list; + } + // if we are close to the end of the list with the current page then we have again a predefined list + if (finish - pos4 <= 3) { + const list = []; + list.push(1); + list.push('...'); + const listRemaining = Array(this.__visiblePages) + .fill() + .map((_, idx) => this.count - this.__visiblePages + 1 + idx); + return list.concat(listRemaining); + } + + return [start, '...', pos3, pos4, pos5, '...', finish]; + } + return Array(finish - start + 1) + .fill() + .map((_, idx) => start + idx); + } + + /** + * Get previous or next button template. + * This method can be overridden to apply customized template in wrapper. + * @param {String} label namespace label i.e. next or previous + * @returns {TemplateResult} icon template + * @protected + */ + // eslint-disable-next-line class-methods-use-this + _prevNextIconTemplate(label) { + return label === 'next' ? html` > ` : html` < `; + } + + /** + * Get next or previous button template. + * This method can be overridden to apply customized template in wrapper. + * @param {String} label namespace label i.e. next or previous + * @param {Number} pageNumber page number to be set + * @param {String} namespace namespace prefix for translations + * @returns {TemplateResult} nav item template + * @protected + */ + _prevNextButtonTemplate(label, pageNumber, namespace = 'lion') { + return html` +
  • + +
  • + `; + } + + /** + * Get disabled button template. + * This method can be overridden to apply customized template in wrapper. + * @param {String} label namespace label i.e. next or previous + * @returns {TemplateResult} nav item template + * @protected + */ + _disabledButtonTemplate(label) { + return html` +
  • + +
  • + `; + } + + render() { + return html` + + `; + } +} diff --git a/packages/pagination/test/lion-pagination.test.js b/packages/pagination/test/lion-pagination.test.js new file mode 100644 index 000000000..fa8340dfd --- /dev/null +++ b/packages/pagination/test/lion-pagination.test.js @@ -0,0 +1,127 @@ +import { html, fixture, expect } from '@open-wc/testing'; +import sinon from 'sinon'; + +import '../lion-pagination.js'; + +describe('Pagination', () => { + it('has states for count and current', async () => { + const el = await fixture(html` `); + expect(el.getAttribute('count')).to.equal('4'); + expect(el.getAttribute('current')).to.equal('1'); + el.count = 8; + el.current = 2; + await el.updateComplete; + expect(el.getAttribute('count')).to.equal('8'); + expect(el.getAttribute('current')).to.equal('2'); + }); + + it('disables the previous button if on first page', async () => { + const el = await fixture(html` `); + const buttons = Array.from(el.shadowRoot.querySelectorAll('button')); + expect(buttons[0]).to.has.attribute('disabled'); + }); + + it('disables the next button if on last page', async () => { + const el = await fixture(html` `); + const buttons = Array.from(el.shadowRoot.querySelectorAll('button')); + expect(buttons[buttons.length - 1]).to.has.attribute('disabled'); + }); + + describe('User interaction', () => { + it('can go to previous page with previous button', async () => { + const el = await fixture(html` `); + const buttons = Array.from(el.shadowRoot.querySelectorAll('button')); + buttons[0].click(); + expect(el.current).to.equal(1); + }); + + it('can go to next page with next button', async () => { + const el = await fixture(html` `); + const buttons = Array.from(el.shadowRoot.querySelectorAll('button')); + buttons[buttons.length - 1].click(); + expect(el.current).to.equal(3); + }); + + it('goes to the page when clicking on its button', async () => { + const el = await fixture(html` `); + const buttons = Array.from(el.shadowRoot.querySelectorAll('button')); + buttons[5].click(); + expect(el.current).to.equal(5); + }); + + it('fires current-changed event when interacting with the pagination', async () => { + const changeSpy = sinon.spy(); + const el = await fixture(html` + + `); + const buttons = Array.from(el.shadowRoot.querySelectorAll('button')); + const previous = buttons[0]; + const next = buttons[buttons.length - 1]; + const page5 = buttons[5]; + + previous.click(); + expect(changeSpy).to.have.callCount(1); + + next.click(); + expect(changeSpy).to.have.callCount(2); + + page5.click(); + expect(changeSpy).to.have.callCount(3); + + el.current = 3; + expect(changeSpy).to.have.callCount(4); + }); + + it('does NOT fire current-changed event when clicking on a current page number', async () => { + const changeSpy = sinon.spy(); + const el = await fixture(html` + + `); + const page2 = el.shadowRoot.querySelector("button[aria-current='true']"); + page2.click(); + expect(changeSpy).to.not.be.called; + expect(el.current).to.equal(2); + }); + + it('should goto next and previous page using `next()` and `previous()`', async () => { + const el = await fixture(html` `); + el.next(); + expect(el.current).to.equal(3); + el.previous(); + expect(el.current).to.equal(2); + }); + + it('should goto first and last page using `first()` and `last()`', async () => { + const el = await fixture(html` `); + expect(el.current).to.equal(2); + el.first(); + expect(el.current).to.equal(1); + el.last(); + expect(el.current).to.equal(5); + }); + + it('should goto 7 page using `goto()`', async () => { + const el = await fixture(html` `); + expect(el.current).to.equal(2); + el.goto(7); + expect(el.current).to.equal(7); + }); + }); + + describe('Accessibility', () => { + it('sets aria-current to the current page', async () => { + const el = await fixture(html` `); + const buttons = Array.from(el.shadowRoot.querySelectorAll('button')); + // button[0] is the previous button + expect(buttons[1].getAttribute('aria-current')).to.equal('true'); + expect(buttons[2].getAttribute('aria-current')).to.equal('false'); + expect(buttons[3].getAttribute('aria-current')).to.equal('false'); + + el.current = 2; + await el.updateComplete; + expect(buttons[1].getAttribute('aria-current')).to.equal('false'); + expect(buttons[2].getAttribute('aria-current')).to.equal('true'); + expect(buttons[3].getAttribute('aria-current')).to.equal('false'); + }); + }); +}); diff --git a/packages/pagination/translations/bg.js b/packages/pagination/translations/bg.js new file mode 100644 index 000000000..a1217f9d2 --- /dev/null +++ b/packages/pagination/translations/bg.js @@ -0,0 +1,6 @@ +export default { + label: 'Навигация по страниците', + previous: 'Предишна страница', + next: 'Следваща страница', + page: 'Страница {page}', +}; diff --git a/packages/pagination/translations/cs.js b/packages/pagination/translations/cs.js new file mode 100644 index 000000000..0b1f2274a --- /dev/null +++ b/packages/pagination/translations/cs.js @@ -0,0 +1,6 @@ +export default { + label: 'Navigace stránky', + previous: 'Předchozí strana', + next: 'Další strana', + page: 'Strana {page}', +}; diff --git a/packages/pagination/translations/de.js b/packages/pagination/translations/de.js new file mode 100644 index 000000000..e6c988397 --- /dev/null +++ b/packages/pagination/translations/de.js @@ -0,0 +1,6 @@ +export default { + label: 'Seitennavigation', + previous: 'Vorherige Seite', + next: 'Nächste Seite', + page: 'Seite {page}', +}; diff --git a/packages/pagination/translations/en.js b/packages/pagination/translations/en.js new file mode 100644 index 000000000..66d5785d0 --- /dev/null +++ b/packages/pagination/translations/en.js @@ -0,0 +1,6 @@ +export default { + label: 'Page navigation', + previous: 'Previous page', + next: 'Next page', + page: 'Page {page}', +}; diff --git a/packages/pagination/translations/es.js b/packages/pagination/translations/es.js new file mode 100644 index 000000000..e0ad83233 --- /dev/null +++ b/packages/pagination/translations/es.js @@ -0,0 +1,6 @@ +export default { + label: 'Navegación de la página', + previous: 'Página anterior', + next: 'Página siguiente', + page: 'Página {page}', +}; diff --git a/packages/pagination/translations/fr.js b/packages/pagination/translations/fr.js new file mode 100644 index 000000000..89020e2b5 --- /dev/null +++ b/packages/pagination/translations/fr.js @@ -0,0 +1,6 @@ +export default { + label: 'Navigation de page', + previous: 'Page précédente', + next: 'Page suivante', + page: 'Page {page}', +}; diff --git a/packages/pagination/translations/hu.js b/packages/pagination/translations/hu.js new file mode 100644 index 000000000..bd4aa9afc --- /dev/null +++ b/packages/pagination/translations/hu.js @@ -0,0 +1,6 @@ +export default { + label: 'Oldalnavigáció', + previous: 'Előző oldal', + next: 'Következő oldal', + page: '{page}. oldal', +}; diff --git a/packages/pagination/translations/it.js b/packages/pagination/translations/it.js new file mode 100644 index 000000000..b0ed57a60 --- /dev/null +++ b/packages/pagination/translations/it.js @@ -0,0 +1,6 @@ +export default { + label: 'Navigazione pagina', + previous: 'Pagina Precedente', + next: 'Pagina successiva', + page: 'Pagina {page}', +}; diff --git a/packages/pagination/translations/nl.js b/packages/pagination/translations/nl.js new file mode 100644 index 000000000..508518f8b --- /dev/null +++ b/packages/pagination/translations/nl.js @@ -0,0 +1,6 @@ +export default { + label: 'Pagina navigatie', + previous: 'Vorige pagina', + next: 'Volgende pagina', + page: 'Pagina {page}', +}; diff --git a/packages/pagination/translations/pl.js b/packages/pagination/translations/pl.js new file mode 100644 index 000000000..6166d008c --- /dev/null +++ b/packages/pagination/translations/pl.js @@ -0,0 +1,6 @@ +export default { + label: 'Nawigacja strony', + previous: 'Poprzednia strona', + next: 'Następna strona', + page: 'Strona {page}', +}; diff --git a/packages/pagination/translations/ro.js b/packages/pagination/translations/ro.js new file mode 100644 index 000000000..cbb0ce913 --- /dev/null +++ b/packages/pagination/translations/ro.js @@ -0,0 +1,6 @@ +export default { + label: 'Navigare în pagină', + previous: 'Pagină anterioară', + next: 'Pagină următoare', + page: 'Pagina {page}', +}; diff --git a/packages/pagination/translations/ru.js b/packages/pagination/translations/ru.js new file mode 100644 index 000000000..fb950b467 --- /dev/null +++ b/packages/pagination/translations/ru.js @@ -0,0 +1,6 @@ +export default { + label: 'Навигация по страницам', + previous: 'Предыдущая страница', + next: 'Следующая страница', + page: 'Страница {page}', +}; diff --git a/packages/pagination/translations/sk.js b/packages/pagination/translations/sk.js new file mode 100644 index 000000000..c7d1b8d3e --- /dev/null +++ b/packages/pagination/translations/sk.js @@ -0,0 +1,6 @@ +export default { + label: 'Navigácia stranami', + previous: 'Predchádzajúca strana', + next: 'Ďalšia strana', + page: 'Strana {page}', +}; diff --git a/packages/pagination/translations/uk.js b/packages/pagination/translations/uk.js new file mode 100644 index 000000000..ce25d7bbd --- /dev/null +++ b/packages/pagination/translations/uk.js @@ -0,0 +1,6 @@ +export default { + label: 'Навігація по сторінках', + previous: 'Попередня сторінка', + next: 'Наступна сторінка', + page: 'Сторінка {page}', +}; diff --git a/packages/pagination/translations/zh.js b/packages/pagination/translations/zh.js new file mode 100644 index 000000000..ea9bd1a78 --- /dev/null +++ b/packages/pagination/translations/zh.js @@ -0,0 +1,6 @@ +export default { + label: '页面导航', + previous: '上一页', + next: '下一页', + page: '页 {page}', +};