auto detect language. Input field in contribution form removed.

This commit is contained in:
Moriz Wahl 2021-01-19 21:52:10 +01:00 committed by Ulf Gebhardt
parent 5559a9bc06
commit 250d231a74
No known key found for this signature in database
GPG Key ID: 81308EFE29ABFEBD
7 changed files with 59 additions and 109 deletions

View File

@ -12,17 +12,30 @@ const setPostLanguage = (text) => {
const lngDetector = new LanguageDetect() const lngDetector = new LanguageDetect()
lngDetector.setLanguageType('iso2') lngDetector.setLanguageType('iso2')
const result = lngDetector.detect(removeHtmlTags(text), 2) const result = lngDetector.detect(removeHtmlTags(text), 2)
return result[0][0] return {
language: result[0][0],
languageScore: result[0][1],
secondaryLanguage: result[1][0],
secondaryLanguageScore: result[1][1],
}
} }
export default { export default {
Mutation: { Mutation: {
CreatePost: async (resolve, root, args, context, info) => { CreatePost: async (resolve, root, args, context, info) => {
args.language = await setPostLanguage(args.content) const languages = await setPostLanguage(args.content)
args = {
...args,
...languages,
}
return resolve(root, args, context, info) return resolve(root, args, context, info)
}, },
UpdatePost: async (resolve, root, args, context, info) => { UpdatePost: async (resolve, root, args, context, info) => {
args.language = await setPostLanguage(args.content) const languages = await setPostLanguage(args.content)
args = {
...args,
...languages,
}
return resolve(root, args, context, info) return resolve(root, args, context, info)
}, },
}, },

View File

@ -25,13 +25,16 @@ beforeAll(async () => {
}) })
afterAll(async () => { afterAll(async () => {
// await cleanDatabase() await cleanDatabase()
}) })
const createPostMutation = gql` const createPostMutation = gql`
mutation($title: String!, $content: String!, $categoryIds: [ID]) { mutation($title: String!, $content: String!, $categoryIds: [ID]) {
CreatePost(title: $title, content: $content, categoryIds: $categoryIds) { CreatePost(title: $title, content: $content, categoryIds: $categoryIds) {
language language
languageScore
secondaryLanguage
secondaryLanguageScore
} }
} }
` `
@ -58,15 +61,17 @@ describe('languagesMiddleware', () => {
...variables, ...variables,
content: 'Jeder sollte vor seiner eigenen Tür kehren.', content: 'Jeder sollte vor seiner eigenen Tür kehren.',
} }
await expect( const response = await mutate({
mutate({
mutation: createPostMutation, mutation: createPostMutation,
variables, variables,
}), })
).resolves.toMatchObject({ expect(response).toMatchObject({
data: { data: {
CreatePost: { CreatePost: {
language: 'de', language: 'de',
languageScore: 0.5134188034188034,
secondaryLanguage: 'no',
secondaryLanguageScore: 0.3655555555555555,
}, },
}, },
}) })
@ -77,15 +82,17 @@ describe('languagesMiddleware', () => {
...variables, ...variables,
content: 'A journey of a thousand miles begins with a single step.', content: 'A journey of a thousand miles begins with a single step.',
} }
await expect( const response = await mutate({
mutate({
mutation: createPostMutation, mutation: createPostMutation,
variables, variables,
}), })
).resolves.toMatchObject({ expect(response).toMatchObject({
data: { data: {
CreatePost: { CreatePost: {
language: 'en', language: 'en',
languageScore: 0.3430188679245283,
secondaryLanguage: 'da',
secondaryLanguageScore: 0.19968553459119498,
}, },
}, },
}) })
@ -96,15 +103,17 @@ describe('languagesMiddleware', () => {
...variables, ...variables,
content: 'A caballo regalado, no le mires el diente.', content: 'A caballo regalado, no le mires el diente.',
} }
await expect( const response = await mutate({
mutate({
mutation: createPostMutation, mutation: createPostMutation,
variables, variables,
}), })
).resolves.toMatchObject({ expect(response).toMatchObject({
data: { data: {
CreatePost: { CreatePost: {
language: 'es', language: 'es',
languageScore: 0.46589743589743593,
secondaryLanguage: 'pt',
secondaryLanguageScore: 0.3834188034188034,
}, },
}, },
}) })
@ -116,15 +125,17 @@ describe('languagesMiddleware', () => {
content: content:
'<strong>Jeder</strong> <strike>sollte</strike> <strong>vor</strong> <span>seiner</span> eigenen <blockquote>Tür</blockquote> kehren.', '<strong>Jeder</strong> <strike>sollte</strike> <strong>vor</strong> <span>seiner</span> eigenen <blockquote>Tür</blockquote> kehren.',
} }
await expect( const response = await mutate({
mutate({
mutation: createPostMutation, mutation: createPostMutation,
variables, variables,
}), })
).resolves.toMatchObject({ expect(response).toMatchObject({
data: { data: {
CreatePost: { CreatePost: {
language: 'de', language: 'de',
languageScore: 0.5134188034188034,
secondaryLanguage: 'no',
secondaryLanguageScore: 0.3655555555555555,
}, },
}, },
}) })

View File

@ -317,19 +317,6 @@ describe('CreatePost', () => {
expected, expected,
) )
}) })
describe('language', () => {
beforeEach(() => {
variables = { ...variables, language: 'es' }
})
it('allows a user to set the language of the post', async () => {
const expected = { data: { CreatePost: { language: 'es' } } }
await expect(mutate({ mutation: createPostMutation, variables })).resolves.toMatchObject(
expected,
)
})
})
}) })
}) })

View File

@ -122,6 +122,9 @@ type Post {
createdAt: String createdAt: String
updatedAt: String updatedAt: String
language: String language: String
languageScore: Float
secondaryLanguage: String
secondaryLanguageScore: Float
pinnedAt: String @cypher( pinnedAt: String @cypher(
statement: "MATCH (this)<-[pinned:PINNED]-(:User) WHERE NOT this.deleted = true AND NOT this.disabled = true RETURN pinned.createdAt" statement: "MATCH (this)<-[pinned:PINNED]-(:User) WHERE NOT this.deleted = true AND NOT this.disabled = true RETURN pinned.createdAt"
) )

View File

@ -23,9 +23,7 @@ describe('ContributionForm.vue', () => {
cancelBtn, cancelBtn,
mocks, mocks,
propsData, propsData,
categoryIds, categoryIds
englishLanguage,
deutschLanguage
const postTitle = 'this is a title for a post' const postTitle = 'this is a title for a post'
const postTitleTooShort = 'xx' const postTitleTooShort = 'xx'
let postTitleTooLong = '' let postTitleTooLong = ''
@ -52,7 +50,6 @@ describe('ContributionForm.vue', () => {
slug: 'this-is-a-title-for-a-post', slug: 'this-is-a-title-for-a-post',
content: postContent, content: postContent,
contentExcerpt: postContent, contentExcerpt: postContent,
language: 'en',
categoryIds, categoryIds,
}, },
}, },
@ -109,10 +106,6 @@ describe('ContributionForm.vue', () => {
postTitleInput = wrapper.find('.ds-input') postTitleInput = wrapper.find('.ds-input')
postTitleInput.setValue(postTitle) postTitleInput.setValue(postTitle)
await wrapper.vm.updateEditorContent(postContent) await wrapper.vm.updateEditorContent(postContent)
englishLanguage = wrapper
.findAll('li')
.filter((language) => language.text() === 'English')
englishLanguage.trigger('click')
}) })
it('title cannot be empty', async () => { it('title cannot be empty', async () => {
@ -147,7 +140,6 @@ describe('ContributionForm.vue', () => {
variables: { variables: {
title: postTitle, title: postTitle,
content: postContent, content: postContent,
language: 'en',
id: null, id: null,
image: null, image: null,
}, },
@ -155,10 +147,6 @@ describe('ContributionForm.vue', () => {
postTitleInput = wrapper.find('.ds-input') postTitleInput = wrapper.find('.ds-input')
postTitleInput.setValue(postTitle) postTitleInput.setValue(postTitle)
await wrapper.vm.updateEditorContent(postContent) await wrapper.vm.updateEditorContent(postContent)
englishLanguage = wrapper
.findAll('li')
.filter((language) => language.text() === 'English')
englishLanguage.trigger('click')
await Vue.nextTick() await Vue.nextTick()
await Vue.nextTick() await Vue.nextTick()
}) })
@ -168,16 +156,6 @@ describe('ContributionForm.vue', () => {
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams)) expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
}) })
it('supports changing the language', async () => {
expectedParams.variables.language = 'de'
deutschLanguage = wrapper
.findAll('li')
.filter((language) => language.text() === 'Deutsch')
deutschLanguage.trigger('click')
wrapper.find('form').trigger('submit')
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
})
it('supports adding a teaser image', async () => { it('supports adding a teaser image', async () => {
expectedParams.variables.image = { expectedParams.variables.image = {
aspectRatio: null, aspectRatio: null,
@ -236,10 +214,6 @@ describe('ContributionForm.vue', () => {
postTitleInput.setValue(postTitle) postTitleInput.setValue(postTitle)
await wrapper.vm.updateEditorContent(postContent) await wrapper.vm.updateEditorContent(postContent)
categoryIds = ['cat12'] categoryIds = ['cat12']
englishLanguage = wrapper
.findAll('li')
.filter((language) => language.text() === 'English')
englishLanguage.trigger('click')
await Vue.nextTick() await Vue.nextTick()
await Vue.nextTick() await Vue.nextTick()
}) })
@ -260,7 +234,6 @@ describe('ContributionForm.vue', () => {
slug: 'dies-ist-ein-post', slug: 'dies-ist-ein-post',
title: 'dies ist ein Post', title: 'dies ist ein Post',
content: 'auf Deutsch geschrieben', content: 'auf Deutsch geschrieben',
language: 'de',
image, image,
categories: [ categories: [
{ {
@ -290,7 +263,6 @@ describe('ContributionForm.vue', () => {
slug: 'this-is-a-title-for-a-post', slug: 'this-is-a-title-for-a-post',
content: postContent, content: postContent,
contentExcerpt: postContent, contentExcerpt: postContent,
language: 'en',
categoryIds, categoryIds,
}, },
}, },
@ -301,7 +273,6 @@ describe('ContributionForm.vue', () => {
variables: { variables: {
title: propsData.contribution.title, title: propsData.contribution.title,
content: propsData.contribution.content, content: propsData.contribution.content,
language: propsData.contribution.language,
id: propsData.contribution.id, id: propsData.contribution.id,
image: { image: {
sensitive: false, sensitive: false,

View File

@ -50,17 +50,6 @@
{{ contentLength }} {{ contentLength }}
<base-icon v-if="errors && errors.content" name="warning" /> <base-icon v-if="errors && errors.content" name="warning" />
</ds-chip> </ds-chip>
<ds-select
model="language"
icon="globe"
class="select-field"
:options="languageOptions"
:placeholder="$t('contribution.languageSelectText')"
:label="$t('contribution.languageSelectLabel')"
/>
<ds-chip v-if="errors && errors.language" size="base" color="danger">
<base-icon name="warning" />
</ds-chip>
<div class="buttons"> <div class="buttons">
<base-button data-test="cancel-button" :disabled="loading" @click="$router.back()" danger> <base-button data-test="cancel-button" :disabled="loading" @click="$router.back()" danger>
{{ $t('actions.cancel') }} {{ $t('actions.cancel') }}
@ -76,10 +65,8 @@
<script> <script>
import gql from 'graphql-tag' import gql from 'graphql-tag'
import orderBy from 'lodash/orderBy'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import HcEditor from '~/components/Editor/Editor' import HcEditor from '~/components/Editor/Editor'
import locales from '~/locales'
import PostMutations from '~/graphql/PostMutations.js' import PostMutations from '~/graphql/PostMutations.js'
import ImageUploader from '~/components/ImageUploader/ImageUploader' import ImageUploader from '~/components/ImageUploader/ImageUploader'
import links from '~/constants/links.js' import links from '~/constants/links.js'
@ -96,11 +83,7 @@ export default {
}, },
}, },
data() { data() {
const { title, content, image, language } = this.contribution const { title, content, image } = this.contribution
const languageOptions = orderBy(locales, 'name').map((locale) => {
return { label: locale.name, value: locale.code }
})
const { sensitive: imageBlurred = false, aspectRatio: imageAspectRatio = null } = image || {} const { sensitive: imageBlurred = false, aspectRatio: imageAspectRatio = null } = image || {}
return { return {
@ -111,15 +94,12 @@ export default {
image: image || null, image: image || null,
imageAspectRatio, imageAspectRatio,
imageBlurred, imageBlurred,
language: languageOptions.find((option) => option.value === language) || null,
}, },
formSchema: { formSchema: {
title: { required: true, min: 3, max: 100 }, title: { required: true, min: 3, max: 100 },
content: { required: true }, content: { required: true },
language: { required: true },
imageBlurred: { required: false }, imageBlurred: { required: false },
}, },
languageOptions,
loading: false, loading: false,
users: [], users: [],
hashtags: [], hashtags: [],
@ -155,7 +135,6 @@ export default {
title, title,
content, content,
id: this.contribution.id || null, id: this.contribution.id || null,
language: this.formData.language.value,
image, image,
}, },
}) })

View File

@ -3,20 +3,8 @@ import gql from 'graphql-tag'
export default () => { export default () => {
return { return {
CreatePost: gql` CreatePost: gql`
mutation( mutation($title: String!, $content: String!, $categoryIds: [ID], $image: ImageInput) {
$title: String! CreatePost(title: $title, content: $content, categoryIds: $categoryIds, image: $image) {
$content: String!
$language: String
$categoryIds: [ID]
$image: ImageInput
) {
CreatePost(
title: $title
content: $content
language: $language
categoryIds: $categoryIds
image: $image
) {
title title
slug slug
content content
@ -34,7 +22,6 @@ export default () => {
$id: ID! $id: ID!
$title: String! $title: String!
$content: String! $content: String!
$language: String
$image: ImageInput $image: ImageInput
$categoryIds: [ID] $categoryIds: [ID]
) { ) {
@ -42,7 +29,6 @@ export default () => {
id: $id id: $id
title: $title title: $title
content: $content content: $content
language: $language
image: $image image: $image
categoryIds: $categoryIds categoryIds: $categoryIds
) { ) {