Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add i18n #205

Merged
merged 31 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
89e8e3c
chore: add a more complex guillotina example
rboixaderg Dec 17, 2023
87a5d9c
chore: add a vite example to run tests
rboixaderg Dec 17, 2023
9861358
chore: update cypress and adapt tests
rboixaderg Dec 17, 2023
0e6803a
chore: github actions
rboixaderg Dec 17, 2023
e93fc6d
chore: gitignore
rboixaderg Dec 17, 2023
4176f26
chore: run guillotina docker
rboixaderg Dec 17, 2023
7c6bf40
chore: dockerfile
rboixaderg Dec 17, 2023
10c794d
chore: config e2e
rboixaderg Dec 17, 2023
b1eb970
chore: github actions, run docker
rboixaderg Dec 17, 2023
203164b
chore: github actions
rboixaderg Dec 17, 2023
a721120
chore: github actions
rboixaderg Dec 17, 2023
b102c88
chore: githubactions uses node 20
rboixaderg Dec 17, 2023
a52b203
fix: layout public images
rboixaderg Dec 17, 2023
46871fd
chore: cypress config
rboixaderg Dec 17, 2023
d55364a
chore: cypress config timeouts
rboixaderg Dec 17, 2023
1b2877b
chore: github actions
rboixaderg Dec 18, 2023
7c7d928
styles: items panel, filter tags
rboixaderg Dec 26, 2023
2660723
fix: edit component, select
rboixaderg Dec 26, 2023
cd3eed0
feat: guillotina example, GMI interface
rboixaderg Dec 26, 2023
ae615f2
test: content search filters
rboixaderg Dec 26, 2023
8405c63
test: add more tests
rboixaderg Dec 29, 2023
1de67fb
chore: versions
rboixaderg Dec 29, 2023
3733f0f
feat: image attachment behavior, upload scale images
rboixaderg Dec 30, 2023
2df459c
feat: render text instead of keys in vocabularies and select options
rboixaderg Dec 31, 2023
140167e
chore: delete e2e old example
rboixaderg Dec 31, 2023
a330e7b
chore: changelog
rboixaderg Dec 31, 2023
d7ea7e0
chore: export components
rboixaderg Jan 1, 2024
fffa2a3
feat: add i18n / react-intl
rboixaderg Jan 5, 2024
6d5bd21
Merge branch 'add-i18n' into add-i18n-b
rboixaderg Jan 5, 2024
8d0e955
test: passing tests
rboixaderg Jan 5, 2024
d351887
test: language test
rboixaderg Jan 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"plugins": [
[
"formatjs",
{
"idInterpolationPattern": "[sha512:contenthash:base64:6]",
"ast": true
}
]
]
}
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- Add filter schema to registry to create dynamic filters in items tab
- Render text value instead of key value in vocabulary select
- Create scale images in IImageAttachment behavior
- Add i18n ( english, catalan, spanish)


0.23.1
Expand Down
2 changes: 1 addition & 1 deletion e2e/cypress/integration/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ LOGIN_TYPES.forEach((loginType) => {

cy.get(CONTEXT_TOOLBAR_SELECTORS.selectFilteType).select('Item')
cy.wait('@get-object-@search**')
cy.get(ITEMS_PANELS_SELECTORS.table).should('contain', 'Anything here!')
cy.get(ITEMS_PANELS_SELECTORS.table).should('contain', 'No results')

cy.visit(
`/${Cypress.env('GUILLOTINA_DB')}/${Cypress.env(
Expand Down
2 changes: 1 addition & 1 deletion e2e/cypress/integration/content.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ LOGIN_TYPES.forEach((loginType) => {
})

cy.get(USER_FORM_SELECTORS.btnUpate).click()
cy.get(NOTIFICATION_SELECTOR).should('contain', 'Data updated')
cy.get(NOTIFICATION_SELECTOR).should('contain', 'User updated')
cy.get(`[data-test='${BREADCRUMB_SELECTORS.prefixItem}-users']`).click()

// Delete Item
Expand Down
2 changes: 1 addition & 1 deletion e2e/cypress/integration/gmi-type-content.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ LOGIN_TYPES.forEach((loginType) => {
})

cy.wait('@patch-object-test-gmi-item/@upload/**')
cy.get(NOTIFICATION_SELECTOR).should('contain', `file uploaded!`)
cy.get(NOTIFICATION_SELECTOR).should('contain', `File uploaded!`)

// Upload image
cy.get(`[data-test='formImageAttachmentTest']`).within(() => {
Expand Down
53 changes: 53 additions & 0 deletions e2e/cypress/integration/language.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { ITEMS_PANELS_SELECTORS } from '../elements/panels-selectors'

describe('check languages', function () {
beforeEach('clear', function () {
cy.clearLocalStorage()
cy.clearCookies()
})

it('Check eng language', function () {
cy.containerLogin()
cy.findAllByText('Addons').click()
cy.findAllByText('Install')
cy.findAllByText('Remove')
cy.findAllByText('Available Addons')
cy.findAllByText('Installed Addons')
cy.findAllByText('Actions').click()
cy.findAllByText('Delete')
cy.findAllByText('Move to...')
cy.findAllByText('Copy to...')
})

it('Check ca language', function () {
cy.containerLogin({
language: 'ca',
})
cy.findAllByText('Addons').click()
cy.findAllByText('Instal·la')
cy.findAllByText('Elimina')
cy.findAllByText('Addons Disponibles')
cy.findAllByText('Addons Instal·lats')

cy.findAllByText('Actions').click()
cy.findAllByText('Elimina')
cy.findAllByText('Mou a...')
cy.findAllByText('Copia a...')
})

it('Check es language', function () {
cy.containerLogin({
language: 'es',
})
cy.findAllByText('Addons').click()
cy.findAllByText('Instalar')
cy.findAllByText('Eliminar')
cy.findAllByText('Complementos Disponibles')
cy.findAllByText('Complementos Instalados')

cy.findAllByText('Actions').click()
cy.findAllByText('Eliminar')
cy.findAllByText('Mover a...')
cy.findAllByText('Copiar a...')
})
})
16 changes: 12 additions & 4 deletions e2e/cypress/support/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { BREADCRUMB_SELECTORS } from '../elements/breadcrumb-selectors'

Cypress.Commands.add(
'autologin',
function ({ username, password, api_url } = {}) {
function ({ username, password, api_url, language = 'en' } = {}) {
const url = api_url || Cypress.env('GUILLOTINA')
const user = username || 'root'
const pw = password || 'root'
Expand All @@ -21,7 +21,11 @@ Cypress.Commands.add(
cy.setLocalStorage('auth_expires', new Date(response.body.exp).getTime())
})

cy.visit('/')
cy.visit('/', {
onBeforeLoad(win) {
Object.defineProperty(win.navigator, 'language', { value: language })
},
})
cy.get('.box > .container').should('be.visible')
}
)
Expand Down Expand Up @@ -66,14 +70,18 @@ Cypress.Commands.add(

Cypress.Commands.add(
'containerLogin',
function ({ username, password, api_url } = {}) {
function ({ username, password, api_url, language = 'en' } = {}) {
cy.intercept('POST', `/@login`).as('login')
const url = api_url || Cypress.env('GUILLOTINA')
const user = username || 'root'
const pw = password || 'root'

cy.interceptPostObject('@login')
cy.visit('/')
cy.visit('/', {
onBeforeLoad(win) {
Object.defineProperty(win.navigator, 'language', { value: language })
},
})
cy.get(LOGIN_SELECTORS.form).should('be.visible')
cy.get(LOGIN_SELECTORS.username).type('root').should('have.value', 'root')
cy.get(LOGIN_SELECTORS.password).type('root').should('have.value', 'root')
Expand Down
4 changes: 3 additions & 1 deletion e2e/vite_example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ function App() {
const [currentSchema, setCurrentSchema] = useState('/')
const [clientInstance, setClientInstance] = useState(undefined)
const [isLogged, setLogged] = useState(auth.isLogged)
console.log('auth is logged', auth.isLogged)

useEffect(() => {
setClientInstance(getClient(url, currentSchema, auth))
}, [currentSchema])
Expand All @@ -127,11 +127,13 @@ function App() {
return null
}

console.log('language', navigator.language)
return (
<ClientProvider client={clientInstance}>
<Layout auth={auth} onLogout={onLogout}>
{isLogged && (
<Guillotina
locale={navigator.language || 'en'}
auth={auth}
url={currentSchema}
registry={{
Expand Down
11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"jwt-decode": "3.1.2",
"prop-types": "15.7.2",
"react-beautiful-dnd": "13.1.1",
"react-intl": "6.5.5",
"react-useportal": "1.0.19",
"uuid": "9.0.1"
},
Expand All @@ -29,9 +30,11 @@
"devDependencies": {
"@babel/cli": "7.12.10",
"@babel/core": "7.12.10",
"@formatjs/cli": "^6.2.4",
"@testing-library/jest-dom": "5.11.6",
"@testing-library/react": "11.2.2",
"@testing-library/user-event": "12.6.0",
"babel-plugin-formatjs": "^10.5.10",
"husky": "4.3.6",
"microbundle": "0.13.0",
"prettier": "2.2.1",
Expand All @@ -47,7 +50,13 @@
"build:js": "rm -rf ./dist && microbundle --jsx React.createElement --no-compress --sourcemap",
"build:css": "rm -rf ./dist/css && mkdir ./dist/css && sass ./src/guillo-gmi/scss/styles.sass ./dist/css/style.css",
"prepublish": "yarn build",
"test": "vitest run"
"test": "vitest run",
"intl-extract": "formatjs extract 'src/**/*.js' --out-file src/guillo-gmi/locales/en.json --id-interpolation-pattern '[sha512:contenthash:base64:6]'",
"intl-compile-en": "formatjs compile src/guillo-gmi/locales/en.json --ast --out-file src/guillo-gmi/locales/compiled/en.json",
"intl-compile-ca": "formatjs compile src/guillo-gmi/locales/ca.json --ast --out-file src/guillo-gmi/locales/compiled/ca.json",
"intl-compile-es": "formatjs compile src/guillo-gmi/locales/es.json --ast --out-file src/guillo-gmi/locales/compiled/es.json",
"intl-compile": "npm run intl-compile-en && npm run intl-compile-es && npm run intl-compile-ca"

},
"eslintConfig": {
"extends": "react-app"
Expand Down
5 changes: 4 additions & 1 deletion src/guillo-gmi/components/behavior_view.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React from 'react'
import { useTraversal } from '../contexts'
import { get } from '../lib/utils'
import { useIntl } from 'react-intl'
import { genericMessages } from '../locales/generic_messages'

export function BehaviorsView({ context, schema }) {
const Ctx = useTraversal()
Expand Down Expand Up @@ -34,9 +36,10 @@ export function BehaviorsView({ context, schema }) {
}

export function BehaviorNotImplemented() {
const intl = useIntl()
return (
<tr>
<td colSpan="3">Not Implemented</td>
<td colSpan="3">{intl.formatMessage(genericMessages.not_implemented)}</td>
</tr>
)
}
33 changes: 23 additions & 10 deletions src/guillo-gmi/components/behaviors/iimageattachment.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@ import { Delete } from '../ui'
import { Button } from '../input/button'
import { FileUpload } from '../input/upload'
import { Confirm } from '../../components/modal'
import { useIntl } from 'react-intl'
import {
genericFileMessages,
genericMessages,
} from '../../locales/generic_messages'

const _sizesImages = ['large', 'preview', 'mini', 'thumb']

export function IImageAttachment({ properties, values }) {
const intl = useIntl()
const cfg = useConfig()
const Ctx = useTraversal()
const modifyContent = Ctx.hasPerm('guillotina.ModifyContent')
Expand All @@ -22,13 +28,12 @@ export function IImageAttachment({ properties, values }) {

const uploadFile = async (ev) => {
ev.preventDefault()

setLoading(true)
setError(undefined)
const endpoint = `${Ctx.path}@upload/image`
const req = await Ctx.client.upload(endpoint, file)
if (req.status !== 200) {
setError('Failed to upload file')
setError(intl.formatMessage(genericFileMessages.error_upload_file))
setLoading(false)
return
}
Expand All @@ -44,15 +49,19 @@ export function IImageAttachment({ properties, values }) {
}

if (hasError) {
setError(`Failed to upload file ${endpointSize}`)
setError(
intl.formatMessage(genericFileMessages.error_upload_file_size, {
size: sizesImages[i],
})
)
setLoading(false)
return
}
}

setFile(undefined)
setLoading(false)
Ctx.flash(`Image uploaded!`, 'success')
Ctx.flash(intl.formatMessage(genericFileMessages.image_uploaded), 'success')
Ctx.refresh()
}

Expand All @@ -62,12 +71,12 @@ export function IImageAttachment({ properties, values }) {
const endpoint = `${Ctx.path}@delete/image`
const req = await Ctx.client.delete(endpoint, file)
if (req.status !== 200) {
setError('Failed to delete file')
setError(intl.formatMessage(genericFileMessages.failed_delete_file))
setLoading(false)
return
}
setLoading(false)
Ctx.flash(`Image deleted!`, 'success')
Ctx.flash(intl.formatMessage(genericFileMessages.image_deleted), 'success')
Ctx.refresh()
}

Expand All @@ -81,12 +90,14 @@ export function IImageAttachment({ properties, values }) {
loading={loading}
onCancel={() => setShowConfirmToDelete(false)}
onConfirm={() => deleteFile()}
message={`Are you sure to remove the image?`}
message={intl.formatMessage(
genericFileMessages.confirm_message_delete_image
)}
/>
)}
{values['image'] && (
<tr>
<td key={1}>Image</td>
<td key={1}>{intl.formatMessage(genericMessages.image)}</td>
<td key={2}>
<div className="is-flex is-align-items-center">
<EditableField
Expand All @@ -111,7 +122,9 @@ export function IImageAttachment({ properties, values }) {
{modifyContent && (
<tr>
<td colSpan={2}>
<label className="label">Upload an image</label>
<label className="label">
{intl.formatMessage(genericFileMessages.upload_an_image)}
</label>
<form
className="is-flex is-align-items-center"
style={{ gap: '15px' }}
Expand All @@ -128,7 +141,7 @@ export function IImageAttachment({ properties, values }) {
onClick={uploadFile}
disabled={!file}
>
Upload
{intl.formatMessage(genericMessages.upload)}
</Button>
</div>
</form>
Expand Down
Loading
Loading