Form Translation (#616)

* Form Translation

* Support for other languages

* Support locale for datepicker

* Apply translation on select input

* Apply translation on select input

* Improve translation

---------

Co-authored-by: Julien Nahum <julien@nahum.net>
This commit is contained in:
Chirag Chhatrala
2024-12-04 23:02:14 +05:30
committed by GitHub
parent c927a235f8
commit daca69267b
36 changed files with 1589 additions and 32 deletions

View File

@@ -27,7 +27,7 @@
<div v-if="isPublicFormPage && form.is_password_protected">
<p class="form-description mb-4 text-gray-700 dark:text-gray-300 px-2">
This form is protected by a password.
{{ $t('forms.password_protected') }}
</p>
<div class="form-group flex flex-wrap w-full">
<div class="relative mb-3 w-full px-2">
@@ -47,7 +47,7 @@
class="my-4"
@click="passwordEntered"
>
Submit
{{ $t('forms.submit') }}
</open-form-button>
</div>
</div>
@@ -139,7 +139,7 @@
class="text-gray-400 hover:text-gray-500 dark:text-gray-600 dark:hover:text-gray-500 cursor-pointer hover:underline text-xs"
target="_blank"
>
Powered by <span class="font-semibold">OpnForm</span>
{{ $t('forms.powered_by') }} <span class="font-semibold">{{ $t('app.name') }}</span>
</a>
</p>
</div>
@@ -186,7 +186,7 @@
href="https://opnform.com/?utm_source=form&utm_content=create_form_free"
class="text-nt-blue hover:underline"
>
Create your form for free with OpnForm
{{ $t('forms.create_form_free') }}
</a>
</p>
</div>
@@ -202,7 +202,6 @@
<script>
import OpenForm from './OpenForm.vue'
import OpenFormButton from './OpenFormButton.vue'
import FormTimer from './FormTimer.vue'
import FormCleanings from '../../pages/forms/show/FormCleanings.vue'
import VTransition from '~/components/global/transitions/VTransition.vue'
import {pendingSubmission} from "~/composables/forms/pendingSubmission.js"
@@ -211,7 +210,7 @@ import ThemeBuilder from "~/lib/forms/themes/ThemeBuilder.js"
import FirstSubmissionModal from '~/components/open/forms/components/FirstSubmissionModal.vue'
export default {
components: { VTransition, OpenFormButton, OpenForm, FormCleanings, FormTimer, FirstSubmissionModal },
components: { VTransition, OpenFormButton, OpenForm, FormCleanings, FirstSubmissionModal },
props: {
form: { type: Object, required: true },
@@ -225,8 +224,11 @@ export default {
},
setup(props) {
const { setLocale } = useI18n()
const authStore = useAuthStore()
return {
setLocale,
authStore,
authenticated: computed(() => authStore.check),
isIframe: useIsIframe(),
@@ -274,6 +276,17 @@ export default {
return this.authenticated && this.form && this.form.creator_id === this.authStore.user.id
}
},
watch: {
'form.language': {
handler(newLanguage) {
this.setLocale(newLanguage)
},
immediate: true
}
},
beforeUnmount() {
this.setLocale('en')
},
methods: {
submitForm (form, onFailure) {
@@ -346,7 +359,7 @@ export default {
if (this.passwordForm.password !== '' && this.passwordForm.password !== null) {
this.$emit('password-entered', this.passwordForm.password)
} else {
this.addPasswordError('The Password field is required.')
this.addPasswordError(this.$t('forms.password_required'))
}
},
addPasswordError (msg) {

View File

@@ -122,7 +122,7 @@
{{ currentFieldsPageBreak.next_btn_text }}
</open-form-button>
<div v-if="!currentFieldsPageBreak && !isLastPage">
Something is wrong with this form structure. If you're the form owner please contact us.
{{ $t('forms.wrong_form_structure') }}
</div>
</div>
</form>

View File

@@ -329,7 +329,8 @@ export default {
theme: this.theme,
maxCharLimit: (field.max_char_limit) ? parseInt(field.max_char_limit) : null,
showCharLimit: field.show_char_limit || false,
isDark: this.darkMode
isDark: this.darkMode,
locale: (this.form?.language) ? this.form.language : 'en'
}
if (field.type === 'matrix') {

View File

@@ -74,6 +74,14 @@
label="Uppercase Input Labels"
/>
<select-input
name="language"
class="mt-4"
:options="availableLocales"
:form="form"
label="Form Language"
/>
<EditorSectionHeader
icon="heroicons:rectangle-stack-16-solid"
title="Layout & Sizing"
@@ -215,6 +223,7 @@ const form = storeToRefs(workingFormStore).content
const isMounted = ref(false)
const confetti = useConfetti()
const showGoogleFontPicker = ref(false)
const { $i18n } = useNuxtApp()
const user = computed(() => authStore.user)
const workspace = computed(() => workspacesStore.getCurrent)
@@ -225,6 +234,10 @@ const isPro = computed(() => {
return workspace.value.is_pro
})
const availableLocales = computed(() => {
return $i18n.locales?.value.map(locale => ({ name: locale.name, value: locale.code })) ?? []
})
onMounted(() => {
isMounted.value = true
})