From daca69267b3ccff139a278476e3645bfdbbc0888 Mon Sep 17 00:00:00 2001 From: Chirag Chhatrala <60499540+chiragchhatrala@users.noreply.github.com> Date: Wed, 4 Dec 2024 23:02:14 +0530 Subject: [PATCH] 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 --- api/app/Http/Requests/AnswerFormRequest.php | 6 + api/app/Http/Requests/UserFormRequest.php | 1 + api/app/Http/Resources/FormResource.php | 1 + api/app/Models/Forms/Form.php | 3 + api/config/app.php | 6 + api/database/factories/FormFactory.php | 1 + ..._08_133330_add_language_to_forms_table.php | 27 + api/resources/lang/ar/validation.php | 117 ++++ api/resources/lang/fr/validation.php | 117 ++++ api/resources/lang/hi/validation.php | 117 ++++ api/resources/lang/ja/validation.php | 117 ++++ api/resources/lang/zh/validation.php | 117 ++++ client/components/forms/DateInput.vue | 2 + client/components/forms/FileInput.vue | 6 +- client/components/forms/FlatSelectInput.vue | 2 +- client/components/forms/SignatureInput.vue | 6 +- .../forms/components/CameraUpload.vue | 13 +- .../components/forms/components/VSelect.vue | 6 +- client/components/forms/useFormInput.js | 3 +- .../open/forms/OpenCompleteForm.vue | 27 +- client/components/open/forms/OpenForm.vue | 2 +- .../components/open/forms/OpenFormField.vue | 3 +- .../form-components/FormCustomization.vue | 13 + client/composables/forms/initForm.js | 1 + client/i18n/lang/ar.json | 38 ++ client/i18n/lang/en.json | 38 ++ client/i18n/lang/es.json | 38 ++ client/i18n/lang/fr.json | 38 ++ client/i18n/lang/hi.json | 38 ++ client/i18n/lang/ja.json | 38 ++ client/i18n/lang/pt.json | 38 ++ client/i18n/lang/zh.json | 38 ++ client/nuxt.config.ts | 19 +- client/package-lock.json | 576 +++++++++++++++++- client/package.json | 1 + client/pages/forms/[slug]/index.vue | 7 +- 36 files changed, 1589 insertions(+), 32 deletions(-) create mode 100644 api/database/migrations/2024_11_08_133330_add_language_to_forms_table.php create mode 100644 api/resources/lang/ar/validation.php create mode 100644 api/resources/lang/fr/validation.php create mode 100644 api/resources/lang/hi/validation.php create mode 100644 api/resources/lang/ja/validation.php create mode 100644 api/resources/lang/zh/validation.php create mode 100644 client/i18n/lang/ar.json create mode 100644 client/i18n/lang/en.json create mode 100644 client/i18n/lang/es.json create mode 100644 client/i18n/lang/fr.json create mode 100644 client/i18n/lang/hi.json create mode 100644 client/i18n/lang/ja.json create mode 100644 client/i18n/lang/pt.json create mode 100644 client/i18n/lang/zh.json diff --git a/api/app/Http/Requests/AnswerFormRequest.php b/api/app/Http/Requests/AnswerFormRequest.php index d3bedae9d..0edc1989d 100644 --- a/api/app/Http/Requests/AnswerFormRequest.php +++ b/api/app/Http/Requests/AnswerFormRequest.php @@ -252,6 +252,12 @@ private function getSelectPropertyOptions($property): array protected function prepareForValidation() { + // Set locale based on form language + if ($this->form?->language && in_array($this->form->language, Form::LANGUAGES)) { + app()->setLocale($this->form->language); + } + + $receivedData = $this->toArray(); $mergeData = []; $countryCodeMapper = json_decode(file_get_contents(resource_path('data/country_code_mapper.json')), true); diff --git a/api/app/Http/Requests/UserFormRequest.php b/api/app/Http/Requests/UserFormRequest.php index bf75ca7d9..2e250634c 100644 --- a/api/app/Http/Requests/UserFormRequest.php +++ b/api/app/Http/Requests/UserFormRequest.php @@ -29,6 +29,7 @@ public function rules() 'visibility' => ['required', Rule::in(Form::VISIBILITY)], // Customization + 'language' => ['required', Rule::in(Form::LANGUAGES)], 'font_family' => 'string|nullable', 'theme' => ['required', Rule::in(Form::THEMES)], 'width' => ['required', Rule::in(Form::WIDTHS)], diff --git a/api/app/Http/Resources/FormResource.php b/api/app/Http/Resources/FormResource.php index 878dd3f6b..93dfeeb38 100644 --- a/api/app/Http/Resources/FormResource.php +++ b/api/app/Http/Resources/FormResource.php @@ -70,6 +70,7 @@ private function getProtectedForm() 'dark_mode' => $this->dark_mode, 'transparent_background' => $this->transparent_background, 'color' => $this->color, + 'language' => $this->language, 'theme' => $this->theme, 'is_password_protected' => true, 'has_password' => $this->has_password, diff --git a/api/app/Models/Forms/Form.php b/api/app/Models/Forms/Form.php index ee8df7f40..6f8dd63a1 100644 --- a/api/app/Models/Forms/Form.php +++ b/api/app/Models/Forms/Form.php @@ -41,6 +41,8 @@ class Form extends Model implements CachableAttributes public const VISIBILITY = ['public', 'draft', 'closed']; + public const LANGUAGES = ['en', 'fr', 'hi', 'es', 'ar', 'zh', 'ja']; + protected $fillable = [ 'workspace_id', 'creator_id', @@ -52,6 +54,7 @@ class Form extends Model implements CachableAttributes 'visibility', // Customization + 'language', 'font_family', 'custom_domain', 'size', diff --git a/api/config/app.php b/api/config/app.php index 51907366d..72b7b02c8 100644 --- a/api/config/app.php +++ b/api/config/app.php @@ -94,6 +94,12 @@ 'locales' => [ 'en' => 'EN', + 'fr' => 'FR', + 'hi' => 'HI', + 'es' => 'ES', + 'ar' => 'AR', + 'zh' => 'ZH', + 'ja' => 'JA', ], /* diff --git a/api/database/factories/FormFactory.php b/api/database/factories/FormFactory.php index a8d91d9d9..91d505e0d 100644 --- a/api/database/factories/FormFactory.php +++ b/api/database/factories/FormFactory.php @@ -50,6 +50,7 @@ public function definition() 'title' => $this->faker->text(30), 'description' => $this->faker->randomHtml(1), 'visibility' => 'public', + 'language' => 'en', 'theme' => $this->faker->randomElement(Form::THEMES), 'size' => $this->faker->randomElement(Form::SIZES), 'border_radius' => $this->faker->randomElement(Form::BORDER_RADIUS), diff --git a/api/database/migrations/2024_11_08_133330_add_language_to_forms_table.php b/api/database/migrations/2024_11_08_133330_add_language_to_forms_table.php new file mode 100644 index 000000000..7a26af408 --- /dev/null +++ b/api/database/migrations/2024_11_08_133330_add_language_to_forms_table.php @@ -0,0 +1,27 @@ +string('language')->default('en'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('forms', function (Blueprint $table) { + $table->dropColumn('language'); + }); + } +}; diff --git a/api/resources/lang/ar/validation.php b/api/resources/lang/ar/validation.php new file mode 100644 index 000000000..da972c907 --- /dev/null +++ b/api/resources/lang/ar/validation.php @@ -0,0 +1,117 @@ + 'يجب قبول :attribute.', + 'active_url' => ':attribute لا يُمثل رابطًا صحيحًا.', + 'after' => 'يجب على :attribute أن يكون تاريخًا لاحقًا للتاريخ :date.', + 'after_or_equal' => ':attribute يجب أن يكون تاريخاً لاحقاً أو مطابقاً للتاريخ :date.', + 'alpha' => 'يجب أن لا يحتوي :attribute سوى على حروف.', + 'alpha_dash' => 'يجب أن لا يحتوي :attribute سوى على حروف، أرقام ومطّات.', + 'alpha_num' => 'يجب أن يحتوي :attribute على حروفٍ وأرقامٍ فقط.', + 'array' => 'يجب أن يكون :attribute ًمصفوفة.', + 'before' => 'يجب على :attribute أن يكون تاريخًا سابقًا للتاريخ :date.', + 'before_or_equal' => ':attribute يجب أن يكون تاريخا سابقا أو مطابقا للتاريخ :date.', + 'between' => [ + 'numeric' => 'يجب أن تكون قيمة :attribute بين :min و :max.', + 'file' => 'يجب أن يكون حجم الملف :attribute بين :min و :max كيلوبايت.', + 'string' => 'يجب أن يكون عدد حروف النّص :attribute بين :min و :max.', + 'array' => 'يجب أن يحتوي :attribute على عدد من العناصر بين :min و :max.', + ], + 'boolean' => 'يجب أن تكون قيمة :attribute إما true أو false.', + 'confirmed' => 'حقل التأكيد غير مُطابق للحقل :attribute.', + 'date' => ':attribute ليس تاريخًا صحيحًا.', + 'date_equals' => 'يجب أن يكون :attribute مطابقاً للتاريخ :date.', + 'date_format' => 'لا يتوافق :attribute مع الشكل :format.', + 'different' => 'يجب أن يكون الحقلان :attribute و :other مُختلفين.', + 'digits' => 'يجب أن يحتوي :attribute على :digits رقمًا/أرقام.', + 'digits_between' => 'يجب أن يحتوي :attribute بين :min و :max رقمًا/أرقام.', + 'dimensions' => 'الـ :attribute يحتوي على أبعاد صورة غير صالحة.', + 'distinct' => 'للحقل :attribute قيمة مُكرّرة.', + 'email' => 'يجب أن يكون :attribute عنوان بريد إلكتروني صحيح البُنية.', + 'ends_with' => 'يجب أن ينتهي :attribute بأحد القيم التالية: :values', + 'exists' => 'القيمة المحددة :attribute غير موجودة.', + 'file' => 'الـ :attribute يجب أن يكون ملفا.', + 'filled' => ':attribute إجباري.', + 'gt' => [ + 'numeric' => 'يجب أن تكون قيمة :attribute أكبر من :value.', + 'file' => 'يجب أن يكون حجم الملف :attribute أكبر من :value كيلوبايت.', + 'string' => 'يجب أن يكون طول النّص :attribute أكثر من :value حروفٍ/حرفًا.', + 'array' => 'يجب أن يحتوي :attribute على أكثر من :value عناصر/عنصر.', + ], + 'gte' => [ + 'numeric' => 'يجب أن تكون قيمة :attribute مساوية أو أكبر من :value.', + 'file' => 'يجب أن يكون حجم الملف :attribute على الأقل :value كيلوبايت.', + 'string' => 'يجب أن يكون طول النص :attribute على الأقل :value حروفٍ/حرفًا.', + 'array' => 'يجب أن يحتوي :attribute على الأقل على :value عُنصرًا/عناصر.', + ], + 'image' => 'يجب أن يكون :attribute صورةً.', + 'in' => ':attribute غير موجود.', + 'in_array' => ':attribute غير موجود في :other.', + 'integer' => 'يجب أن يكون :attribute عددًا صحيحًا.', + 'ip' => 'يجب أن يكون :attribute عنوان IP صحيحًا.', + 'ipv4' => 'يجب أن يكون :attribute عنوان IPv4 صحيحًا.', + 'ipv6' => 'يجب أن يكون :attribute عنوان IPv6 صحيحًا.', + 'json' => 'يجب أن يكون :attribute نصًا من نوع JSON.', + 'lt' => [ + 'numeric' => 'يجب أن تكون قيمة :attribute أصغر من :value.', + 'file' => 'يجب أن يكون حجم الملف :attribute أصغر من :value كيلوبايت.', + 'string' => 'يجب أن يكون طول النّص :attribute أقل من :value حروفٍ/حرفًا.', + 'array' => 'يجب أن يحتوي :attribute على أقل من :value عناصر/عنصر.', + ], + 'lte' => [ + 'numeric' => 'يجب أن تكون قيمة :attribute مساوية أو أصغر من :value.', + 'file' => 'يجب أن لا يتجاوز حجم الملف :attribute :value كيلوبايت.', + 'string' => 'يجب أن لا يتجاوز طول النّص :attribute :value حروفٍ/حرفًا.', + 'array' => 'يجب أن لا يحتوي :attribute على أكثر من :value عناصر/عنصر.', + ], + 'max' => [ + 'numeric' => 'يجب أن تكون قيمة :attribute مساوية أو أصغر من :max.', + 'file' => 'يجب أن لا يتجاوز حجم الملف :attribute :max كيلوبايت.', + 'string' => 'يجب أن لا يتجاوز طول النّص :attribute :max حروفٍ/حرفًا.', + 'array' => 'يجب أن لا يحتوي :attribute على أكثر من :max عناصر/عنصر.', + ], + 'mimes' => 'يجب أن يكون ملفًا من نوع : :values.', + 'mimetypes' => 'يجب أن يكون ملفًا من نوع : :values.', + 'min' => [ + 'numeric' => 'يجب أن تكون قيمة :attribute مساوية أو أكبر من :min.', + 'file' => 'يجب أن يكون حجم الملف :attribute على الأقل :min كيلوبايت.', + 'string' => 'يجب أن يكون طول النص :attribute على الأقل :min حروفٍ/حرفًا.', + 'array' => 'يجب أن يحتوي :attribute على الأقل على :min عُنصرًا/عناصر.', + ], + 'multiple_of' => ':attribute يجب أن يكون من مضاعفات :value', + 'not_in' => 'العنصر :attribute غير صحيح.', + 'not_regex' => 'صيغة :attribute غير صحيحة.', + 'numeric' => 'يجب على :attribute أن يكون رقمًا.', + 'password' => 'كلمة المرور غير صحيحة.', + 'present' => 'يجب تقديم :attribute.', + 'regex' => 'صيغة :attribute غير صحيحة.', + 'required' => ':attribute مطلوب.', + 'required_if' => ':attribute مطلوب في حال ما إذا كان :other يساوي :value.', + 'required_unless' => ':attribute مطلوب في حال ما لم يكن :other يساوي :values.', + 'required_with' => ':attribute مطلوب إذا توفّر :values.', + 'required_with_all' => ':attribute مطلوب إذا توفّر :values.', + 'required_without' => ':attribute مطلوب إذا لم يتوفّر :values.', + 'required_without_all' => ':attribute مطلوب إذا لم يتوفّر :values.', + 'same' => 'يجب أن يتطابق :attribute مع :other.', + 'size' => [ + 'numeric' => 'يجب أن تكون قيمة :attribute مساوية لـ :size.', + 'file' => 'يجب أن يكون حجم الملف :attribute :size كيلوبايت.', + 'string' => 'يجب أن يحتوي النص :attribute على :size حروفٍ/حرفًا بالضبط.', + 'array' => 'يجب أن يحتوي :attribute على :size عنصرٍ/عناصر بالضبط.', + ], + 'starts_with' => 'يجب أن يبدأ :attribute بأحد القيم التالية: :values', + 'string' => 'يجب أن يكون :attribute نصًا.', + 'timezone' => 'يجب أن يكون :attribute نطاقًا زمنيًا صحيحًا.', + 'unique' => 'قيمة :attribute مُستخدمة من قبل.', + 'uploaded' => 'فشل في تحميل الـ :attribute.', + 'url' => 'صيغة الرابط :attribute غير صحيحة.', + 'uuid' => ':attribute يجب أن يكون بصيغة UUID سليمة.', + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'رسالة-مخصصة', + ], + ], + + 'attributes' => [], +]; diff --git a/api/resources/lang/fr/validation.php b/api/resources/lang/fr/validation.php new file mode 100644 index 000000000..242ad3d59 --- /dev/null +++ b/api/resources/lang/fr/validation.php @@ -0,0 +1,117 @@ + 'Le champ :attribute doit être accepté.', + 'active_url' => 'Le champ :attribute n\'est pas une URL valide.', + 'after' => 'Le champ :attribute doit être une date postérieure au :date.', + 'after_or_equal' => 'Le champ :attribute doit être une date postérieure ou égale au :date.', + 'alpha' => 'Le champ :attribute doit contenir uniquement des lettres.', + 'alpha_dash' => 'Le champ :attribute doit contenir uniquement des lettres, des chiffres, des tirets et des underscores.', + 'alpha_num' => 'Le champ :attribute doit contenir uniquement des lettres et des chiffres.', + 'array' => 'Le champ :attribute doit être un tableau.', + 'before' => 'Le champ :attribute doit être une date antérieure au :date.', + 'before_or_equal' => 'Le champ :attribute doit être une date antérieure ou égale au :date.', + 'between' => [ + 'numeric' => 'La valeur de :attribute doit être comprise entre :min et :max.', + 'file' => 'La taille du fichier de :attribute doit être comprise entre :min et :max kilo-octets.', + 'string' => 'Le texte :attribute doit contenir entre :min et :max caractères.', + 'array' => 'Le tableau :attribute doit contenir entre :min et :max éléments.', + ], + 'boolean' => 'Le champ :attribute doit être vrai ou faux.', + 'confirmed' => 'Le champ de confirmation :attribute ne correspond pas.', + 'date' => 'Le champ :attribute n\'est pas une date valide.', + 'date_equals' => 'Le champ :attribute doit être une date égale à :date.', + 'date_format' => 'Le champ :attribute ne correspond pas au format :format.', + 'different' => 'Les champs :attribute et :other doivent être différents.', + 'digits' => 'Le champ :attribute doit contenir :digits chiffres.', + 'digits_between' => 'Le champ :attribute doit contenir entre :min et :max chiffres.', + 'dimensions' => 'Les dimensions de l\'image :attribute ne sont pas valides.', + 'distinct' => 'Le champ :attribute a une valeur en double.', + 'email' => 'Le champ :attribute doit être une adresse e-mail valide.', + 'ends_with' => 'Le champ :attribute doit se terminer par une des valeurs suivantes : :values.', + 'exists' => 'Le champ :attribute sélectionné est invalide.', + 'file' => 'Le champ :attribute doit être un fichier.', + 'filled' => 'Le champ :attribute doit avoir une valeur.', + 'gt' => [ + 'numeric' => 'La valeur de :attribute doit être supérieure à :value.', + 'file' => 'La taille du fichier de :attribute doit être supérieure à :value kilo-octets.', + 'string' => 'Le texte :attribute doit contenir plus de :value caractères.', + 'array' => 'Le tableau :attribute doit contenir plus de :value éléments.', + ], + 'gte' => [ + 'numeric' => 'La valeur de :attribute doit être supérieure ou égale à :value.', + 'file' => 'La taille du fichier de :attribute doit être supérieure ou égale à :value kilo-octets.', + 'string' => 'Le texte :attribute doit contenir au moins :value caractères.', + 'array' => 'Le tableau :attribute doit contenir au moins :value éléments.', + ], + 'image' => 'Le champ :attribute doit être une image.', + 'in' => 'Le champ :attribute est invalide.', + 'in_array' => 'Le champ :attribute n\'existe pas dans :other.', + 'integer' => 'Le champ :attribute doit être un entier.', + 'ip' => 'Le champ :attribute doit être une adresse IP valide.', + 'ipv4' => 'Le champ :attribute doit être une adresse IPv4 valide.', + 'ipv6' => 'Le champ :attribute doit être une adresse IPv6 valide.', + 'json' => 'Le champ :attribute doit être un document JSON valide.', + 'lt' => [ + 'numeric' => 'La valeur de :attribute doit être inférieure à :value.', + 'file' => 'La taille du fichier de :attribute doit être inférieure à :value kilo-octets.', + 'string' => 'Le texte :attribute doit contenir moins de :value caractères.', + 'array' => 'Le tableau :attribute doit contenir moins de :value éléments.', + ], + 'lte' => [ + 'numeric' => 'La valeur de :attribute doit être inférieure ou égale à :value.', + 'file' => 'La taille du fichier de :attribute doit être inférieure ou égale à :value kilo-octets.', + 'string' => 'Le texte :attribute doit contenir au plus :value caractères.', + 'array' => 'Le tableau :attribute doit contenir au plus :value éléments.', + ], + 'max' => [ + 'numeric' => 'La valeur de :attribute ne peut être supérieure à :max.', + 'file' => 'La taille du fichier de :attribute ne peut pas dépasser :max kilo-octets.', + 'string' => 'Le texte de :attribute ne peut contenir plus de :max caractères.', + 'array' => 'Le tableau :attribute ne peut contenir plus de :max éléments.', + ], + 'mimes' => 'Le champ :attribute doit être un fichier de type : :values.', + 'mimetypes' => 'Le champ :attribute doit être un fichier de type : :values.', + 'min' => [ + 'numeric' => 'La valeur de :attribute doit être supérieure ou égale à :min.', + 'file' => 'La taille du fichier de :attribute doit être supérieure à :min kilo-octets.', + 'string' => 'Le texte :attribute doit contenir au moins :min caractères.', + 'array' => 'Le tableau :attribute doit contenir au moins :min éléments.', + ], + 'multiple_of' => 'La valeur de :attribute doit être un multiple de :value', + 'not_in' => 'Le champ :attribute sélectionné n\'est pas valide.', + 'not_regex' => 'Le format du champ :attribute n\'est pas valide.', + 'numeric' => 'Le champ :attribute doit contenir un nombre.', + 'password' => 'Le mot de passe est incorrect.', + 'present' => 'Le champ :attribute doit être présent.', + 'regex' => 'Le format du champ :attribute est invalide.', + 'required' => 'Le champ :attribute est obligatoire.', + 'required_if' => 'Le champ :attribute est obligatoire quand :other est :value.', + 'required_unless' => 'Le champ :attribute est obligatoire sauf si :other est :values.', + 'required_with' => 'Le champ :attribute est obligatoire quand :values est présent.', + 'required_with_all' => 'Le champ :attribute est obligatoire quand :values sont présents.', + 'required_without' => 'Le champ :attribute est obligatoire quand :values n\'est pas présent.', + 'required_without_all' => 'Le champ :attribute est requis quand aucun de :values n\'est présent.', + 'same' => 'Les champs :attribute et :other doivent être identiques.', + 'size' => [ + 'numeric' => 'La valeur de :attribute doit être :size.', + 'file' => 'La taille du fichier de :attribute doit être de :size kilo-octets.', + 'string' => 'Le texte de :attribute doit contenir :size caractères.', + 'array' => 'Le tableau :attribute doit contenir :size éléments.', + ], + 'starts_with' => 'Le champ :attribute doit commencer avec une des valeurs suivantes : :values.', + 'string' => 'Le champ :attribute doit être une chaîne de caractères.', + 'timezone' => 'Le champ :attribute doit être un fuseau horaire valide.', + 'unique' => 'La valeur du champ :attribute est déjà utilisée.', + 'uploaded' => 'Le fichier du champ :attribute n\'a pu être téléversé.', + 'url' => 'Le format de l\'URL de :attribute n\'est pas valide.', + 'uuid' => 'Le champ :attribute doit être un UUID valide.', + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'message-personnalisé', + ], + ], + + 'attributes' => [], +]; diff --git a/api/resources/lang/hi/validation.php b/api/resources/lang/hi/validation.php new file mode 100644 index 000000000..d2960e973 --- /dev/null +++ b/api/resources/lang/hi/validation.php @@ -0,0 +1,117 @@ + ':attribute को स्वीकार किया जाना चाहिए।', + 'active_url' => ':attribute एक मान्य URL नहीं है।', + 'after' => ':attribute, :date के बाद की एक तारीख होनी चाहिए।', + 'after_or_equal' => ':attribute, :date के बाद या उसके बराबर की तारीख होनी चाहिए।', + 'alpha' => ':attribute में केवल अक्षर हो सकते हैं।', + 'alpha_dash' => ':attribute में केवल अक्षर, संख्या, डैश और अंडरस्कोर हो सकते हैं।', + 'alpha_num' => ':attribute में केवल अक्षर और संख्याएं हो सकती हैं।', + 'array' => ':attribute एक एरे होना चाहिए।', + 'before' => ':attribute, :date से पहले की एक तारीख होनी चाहिए।', + 'before_or_equal' => ':attribute, :date से पहले या उसके बराबर की तारीख होनी चाहिए।', + 'between' => [ + 'numeric' => ':attribute, :min और :max के बीच होना चाहिए।', + 'file' => ':attribute, :min और :max किलोबाइट के बीच होना चाहिए।', + 'string' => ':attribute, :min और :max वर्णों के बीच होना चाहिए।', + 'array' => ':attribute, :min और :max आइटमों के बीच होना चाहिए।', + ], + 'boolean' => ':attribute फील्ड सही या गलत होना चाहिए।', + 'confirmed' => ':attribute पुष्टिकरण मेल नहीं खा रहा है।', + 'date' => ':attribute एक मान्य तारीख नहीं है।', + 'date_equals' => ':attribute, :date के बराबर की तारीख होनी चाहिए।', + 'date_format' => ':attribute फॉर्मेट :format से मेल नहीं खा रहा है।', + 'different' => ':attribute और :other अलग होना चाहिए।', + 'digits' => ':attribute, :digits अंक होना चाहिए।', + 'digits_between' => ':attribute, :min और :max अंकों के बीच होना चाहिए।', + 'dimensions' => ':attribute की अमान्य छवि आयाम हैं।', + 'distinct' => ':attribute फील्ड का एक डुप्लिकेट मान है।', + 'email' => ':attribute एक मान्य ईमेल पता होना चाहिए।', + 'ends_with' => ':attribute निम्न में से किसी एक के साथ समाप्त होना चाहिए: :values', + 'exists' => 'चयनित :attribute अमान्य है।', + 'file' => ':attribute एक फ़ाइल होनी चाहिए।', + 'filled' => ':attribute फील्ड आवश्यक है।', + 'gt' => [ + 'numeric' => ':attribute, :value से बड़ा होना चाहिए।', + 'file' => ':attribute, :value किलोबाइट से बड़ा होना चाहिए।', + 'string' => ':attribute, :value वर्णों से बड़ा होना चाहिए।', + 'array' => ':attribute, :value आइटमों से अधिक होना चाहिए।', + ], + 'gte' => [ + 'numeric' => ':attribute, :value से बड़ा या बराबर होना चाहिए।', + 'file' => ':attribute, :value किलोबाइट से बड़ा या बराबर होना चाहिए।', + 'string' => ':attribute, :value वर्णों से बड़ा या बराबर होना चाहिए।', + 'array' => ':attribute में :value आइटम या अधिक होने चाहिए।', + ], + 'image' => ':attribute एक छवि होनी चाहिए।', + 'in' => 'चयनित :attribute अमान्य है।', + 'in_array' => ':attribute फील्ड, :other में मौजूद नहीं है।', + 'integer' => ':attribute एक पूर्णांक होना चाहिए।', + 'ip' => ':attribute एक मान्य IP पता होना चाहिए।', + 'ipv4' => ':attribute एक मान्य IPv4 पता होना चाहिए।', + 'ipv6' => ':attribute एक मान्य IPv6 पता होना चाहिए।', + 'json' => ':attribute एक मान्य JSON स्ट्रिंग होना चाहिए।', + 'lt' => [ + 'numeric' => ':attribute, :value से छोटा होना चाहिए।', + 'file' => ':attribute, :value किलोबाइट से छोटा होना चाहिए।', + 'string' => ':attribute, :value वर्णों से छोटा होना चाहिए।', + 'array' => ':attribute, :value आइटमों से कम होना चाहिए।', + ], + 'lte' => [ + 'numeric' => ':attribute, :value से छोटा या बराबर होना चाहिए।', + 'file' => ':attribute, :value किलोबाइट से छोटा या बराबर होना चाहिए।', + 'string' => ':attribute, :value वर्णों से छोटा या बराबर होना चाहिए।', + 'array' => ':attribute में :value आइटम से अधिक नहीं होना चाहिए।', + ], + 'max' => [ + 'numeric' => ':attribute, :max से बड़ा नहीं हो सकता है।', + 'file' => ':attribute, :max किलोबाइट से बड़ा नहीं हो सकता है।', + 'string' => ':attribute, :max वर्णों से बड़ा नहीं हो सकता है।', + 'array' => ':attribute में :max से अधिक आइटम नहीं हो सकते हैं।', + ], + 'mimes' => ':attribute एक प्रकार की फ़ाइल: :values होनी चाहिए।', + 'mimetypes' => ':attribute एक प्रकार की फ़ाइल: :values होनी चाहिए।', + 'min' => [ + 'numeric' => ':attribute कम से कम :min होना चाहिए।', + 'file' => ':attribute कम से कम :min किलोबाइट होना चाहिए।', + 'string' => ':attribute कम से कम :min वर्ण होना चाहिए।', + 'array' => ':attribute में कम से कम :min आइटम होने चाहिए।', + ], + 'multiple_of' => ':attribute, :value का गुणज होना चाहिए।', + 'not_in' => 'चयनित :attribute अमान्य है।', + 'not_regex' => ':attribute प्रारूप अमान्य है।', + 'numeric' => ':attribute एक संख्या होनी चाहिए।', + 'password' => 'पासवर्ड गलत है।', + 'present' => ':attribute फील्ड मौजूद होना चाहिए।', + 'regex' => ':attribute प्रारूप अमान्य है।', + 'required' => ':attribute फील्ड आवश्यक है।', + 'required_if' => ':attribute फील्ड आवश्यक है जब :other :value है।', + 'required_unless' => ':attribute फील्ड आवश्यक है जब तक :other, :values में नहीं है।', + 'required_with' => ':attribute फील्ड आवश्यक है जब :values मौजूद है।', + 'required_with_all' => ':attribute फील्ड आवश्यक है जब :values मौजूद हैं।', + 'required_without' => ':attribute फील्ड आवश्यक है जब :values मौजूद नहीं है।', + 'required_without_all' => ':attribute फील्ड आवश्यक है जब :values में से कोई भी मौजूद नहीं है।', + 'same' => ':attribute और :other मेल खाने चाहिए।', + 'size' => [ + 'numeric' => ':attribute, :size होना चाहिए।', + 'file' => ':attribute, :size किलोबाइट होना चाहिए।', + 'string' => ':attribute, :size वर्ण होना चाहिए।', + 'array' => ':attribute में :size आइटम होने चाहिए।', + ], + 'starts_with' => ':attribute निम्न में से किसी एक से शुरू होना चाहिए: :values', + 'string' => ':attribute एक स्ट्रिंग होनी चाहिए।', + 'timezone' => ':attribute एक मान्य क्षेत्र होना चाहिए।', + 'unique' => ':attribute पहले से ही लिया गया है।', + 'uploaded' => ':attribute अपलोड करने में विफल रहा।', + 'url' => ':attribute प्रारूप अमान्य है।', + 'uuid' => ':attribute एक मान्य UUID होना चाहिए।', + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'कस्टम-संदेश', + ], + ], + + 'attributes' => [], +]; diff --git a/api/resources/lang/ja/validation.php b/api/resources/lang/ja/validation.php new file mode 100644 index 000000000..fc2f8df63 --- /dev/null +++ b/api/resources/lang/ja/validation.php @@ -0,0 +1,117 @@ + ':attributeを承認してください。', + 'active_url' => ':attributeは、有効なURLではありません。', + 'after' => ':attributeには、:dateより後の日付を指定してください。', + 'after_or_equal' => ':attributeには、:date以降の日付を指定してください。', + 'alpha' => ':attributeには、アルファベッドのみ使用できます。', + 'alpha_dash' => ':attributeには、英数字、ハイフン、アンダースコアのみ使用できます。', + 'alpha_num' => ':attributeには、英数字のみ使用できます。', + 'array' => ':attributeには、配列を指定してください。', + 'before' => ':attributeには、:dateより前の日付を指定してください。', + 'before_or_equal' => ':attributeには、:date以前の日付を指定してください。', + 'between' => [ + 'numeric' => ':attributeには、:minから:maxまでの数字を指定してください。', + 'file' => ':attributeには、:min KBから:max KBまでのサイズのファイルを指定してください。', + 'string' => ':attributeは、:min文字から:max文字にしてください。', + 'array' => ':attributeの項目は、:min個から:max個にしてください。', + ], + 'boolean' => ':attributeには、trueかfalseを指定してください。', + 'confirmed' => ':attributeと確認用の値が一致しません。', + 'date' => ':attributeは、正しい日付ではありません。', + 'date_equals' => ':attributeは:dateと同じ日付でなければなりません。', + 'date_format' => ':attributeの形式は、:formatと合いません。', + 'different' => ':attributeと:otherには、異なった内容を指定してください。', + 'digits' => ':attributeは、:digits桁にしてください。', + 'digits_between' => ':attributeは、:min桁から:max桁にしてください。', + 'dimensions' => ':attributeの画像サイズが無効です。', + 'distinct' => ':attributeの値が重複しています。', + 'email' => ':attributeには、有効なメールアドレスを指定してください。', + 'ends_with' => ':attributeは、次のいずれかで終わる必要があります。: :values', + 'exists' => '選択された:attributeは、有効ではありません。', + 'file' => ':attributeには、ファイルを指定してください。', + 'filled' => ':attributeには、値を指定してください。', + 'gt' => [ + 'numeric' => ':attributeは、:valueより大きくなければなりません。', + 'file' => ':attributeは、:value KBより大きくなければなりません。', + 'string' => ':attributeは、:value文字より長くなければなりません。', + 'array' => ':attributeの項目数は、:value個より多くなければなりません。', + ], + 'gte' => [ + 'numeric' => ':attributeは、:value以上でなければなりません。', + 'file' => ':attributeは、:value KB以上でなければなりません。', + 'string' => ':attributeは、:value文字以上でなければなりません。', + 'array' => ':attributeの項目数は、:value個以上でなければなりません。', + ], + 'image' => ':attributeには、画像を指定してください。', + 'in' => '選択された:attributeは、有効ではありません。', + 'in_array' => ':attributeが:otherに存在しません。', + 'integer' => ':attributeには、整数を指定してください。', + 'ip' => ':attributeには、有効なIPアドレスを指定してください。', + 'ipv4' => ':attributeはIPv4アドレスを指定してください。', + 'ipv6' => ':attributeはIPv6アドレスを指定してください。', + 'json' => ':attributeには、有効なJSON文字列を指定してください。', + 'lt' => [ + 'numeric' => ':attributeは、:valueより小さくなければなりません。', + 'file' => ':attributeは、:value KBより小さくなければなりません。', + 'string' => ':attributeは、:value文字より短くなければなりません。', + 'array' => ':attributeの項目数は、:value個より少なくなければなりません。', + ], + 'lte' => [ + 'numeric' => ':attributeは、:value以下でなければなりません。', + 'file' => ':attributeは、:value KB以下でなければなりません。', + 'string' => ':attributeは、:value文字以下でなければなりません。', + 'array' => ':attributeの項目数は、:value個以下でなければなりません。', + ], + 'max' => [ + 'numeric' => ':attributeには、:max以下の数字を指定してください。', + 'file' => ':attributeには、:max KB以下のファイルを指定してください。', + 'string' => ':attributeは、:max文字以下にしてください。', + 'array' => ':attributeの項目は、:max個以下にしてください。', + ], + 'mimes' => ':attributeには、:valuesタイプのファイルを指定してください。', + 'mimetypes' => ':attributeには、:valuesタイプのファイルを指定してください。', + 'min' => [ + 'numeric' => ':attributeには、:min以上の数字を指定してください。', + 'file' => ':attributeには、:min KB以上のファイルを指定してください。', + 'string' => ':attributeは、:min文字以上にしてください。', + 'array' => ':attributeの項目は、:min個以上にしてください。', + ], + 'multiple_of' => ':attributeは:valueの倍数でなければなりません。', + 'not_in' => '選択された:attributeは、有効ではありません。', + 'not_regex' => ':attributeの形式が無効です。', + 'numeric' => ':attributeには、数字を指定してください。', + 'password' => 'パスワードが正しくありません。', + 'present' => ':attributeが存在している必要があります。', + 'regex' => ':attributeには、有効な正規表現を指定してください。', + 'required' => ':attributeは、必ず指定してください。', + 'required_if' => ':otherが:valueの場合、:attributeを指定してください。', + 'required_unless' => ':otherが:values以外の場合、:attributeを指定してください。', + 'required_with' => ':valuesが指定されている場合、:attributeも指定してください。', + 'required_with_all' => ':valuesが全て指定されている場合、:attributeも指定してください。', + 'required_without' => ':valuesが指定されていない場合、:attributeを指定してください。', + 'required_without_all' => ':valuesが全て指定されていない場合、:attributeを指定してください。', + 'same' => ':attributeと:otherが一致しません。', + 'size' => [ + 'numeric' => ':attributeには、:sizeを指定してください。', + 'file' => ':attributeには、:size KBのファイルを指定してください。', + 'string' => ':attributeは、:size文字にしてください。', + 'array' => ':attributeの項目は、:size個にしてください。', + ], + 'starts_with' => ':attributeは、次のいずれかで始まる必要があります。: :values', + 'string' => ':attributeには、文字を指定してください。', + 'timezone' => ':attributeには、有効なタイムゾーンを指定してください。', + 'unique' => '指定の:attributeは既に使用されています。', + 'uploaded' => ':attributeのアップロードに失敗しました。', + 'url' => ':attributeは、有効なURL形式で指定してください。', + 'uuid' => ':attributeは、有効なUUIDでなければなりません。', + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'カスタムメッセージ', + ], + ], + + 'attributes' => [], +]; diff --git a/api/resources/lang/zh/validation.php b/api/resources/lang/zh/validation.php new file mode 100644 index 000000000..e7bf82dd4 --- /dev/null +++ b/api/resources/lang/zh/validation.php @@ -0,0 +1,117 @@ + ':attribute 必须被接受。', + 'active_url' => ':attribute 不是一个有效的网址。', + 'after' => ':attribute 必须是 :date 之后的日期。', + 'after_or_equal' => ':attribute 必须是 :date 之后或相同的日期。', + 'alpha' => ':attribute 只能由字母组成。', + 'alpha_dash' => ':attribute 只能由字母、数字、短划线和下划线组成。', + 'alpha_num' => ':attribute 只能由字母和数字组成。', + 'array' => ':attribute 必须是一个数组。', + 'before' => ':attribute 必须是 :date 之前的日期。', + 'before_or_equal' => ':attribute 必须是 :date 之前或相同的日期。', + 'between' => [ + 'numeric' => ':attribute 必须介于 :min - :max 之间。', + 'file' => ':attribute 必须介于 :min - :max KB 之间。', + 'string' => ':attribute 必须介于 :min - :max 个字符之间。', + 'array' => ':attribute 必须只有 :min - :max 个单元。', + ], + 'boolean' => ':attribute 必须为布尔值。', + 'confirmed' => ':attribute 两次输入不一致。', + 'date' => ':attribute 不是一个有效的日期。', + 'date_equals' => ':attribute 必须等于 :date。', + 'date_format' => ':attribute 的格式必须为 :format。', + 'different' => ':attribute 和 :other 必须不同。', + 'digits' => ':attribute 必须是 :digits 位数字。', + 'digits_between' => ':attribute 必须是介于 :min 和 :max 位的数字。', + 'dimensions' => ':attribute 图片尺寸不正确。', + 'distinct' => ':attribute 已经存在。', + 'email' => ':attribute 不是一个合法的邮箱。', + 'ends_with' => ':attribute 必须以 :values 为结尾。', + 'exists' => ':attribute 不存在。', + 'file' => ':attribute 必须是文件。', + 'filled' => ':attribute 不能为空。', + 'gt' => [ + 'numeric' => ':attribute 必须大于 :value。', + 'file' => ':attribute 必须大于 :value KB。', + 'string' => ':attribute 必须多于 :value 个字符。', + 'array' => ':attribute 必须多于 :value 个元素。', + ], + 'gte' => [ + 'numeric' => ':attribute 必须大于或等于 :value。', + 'file' => ':attribute 必须大于或等于 :value KB。', + 'string' => ':attribute 必须多于或等于 :value 个字符。', + 'array' => ':attribute 必须多于或等于 :value 个元素。', + ], + 'image' => ':attribute 必须是图片。', + 'in' => '已选的属性 :attribute 无效。', + 'in_array' => ':attribute 必须在 :other 中。', + 'integer' => ':attribute 必须是整数。', + 'ip' => ':attribute 必须是有效的 IP 地址。', + 'ipv4' => ':attribute 必须是有效的 IPv4 地址。', + 'ipv6' => ':attribute 必须是有效的 IPv6 地址。', + 'json' => ':attribute 必须是正确的 JSON 格式。', + 'lt' => [ + 'numeric' => ':attribute 必须小于 :value。', + 'file' => ':attribute 必须小于 :value KB。', + 'string' => ':attribute 必须少于 :value 个字符。', + 'array' => ':attribute 必须少于 :value 个元素。', + ], + 'lte' => [ + 'numeric' => ':attribute 必须小于或等于 :value。', + 'file' => ':attribute 必须小于或等于 :value KB。', + 'string' => ':attribute 必须少于或等于 :value 个字符。', + 'array' => ':attribute 必须少于或等于 :value 个元素。', + ], + 'max' => [ + 'numeric' => ':attribute 不能大于 :max。', + 'file' => ':attribute 不能大于 :max KB。', + 'string' => ':attribute 不能大于 :max 个字符。', + 'array' => ':attribute 最多只有 :max 个单元。', + ], + 'mimes' => ':attribute 必须是一个 :values 类型的文件。', + 'mimetypes' => ':attribute 必须是一个 :values 类型的文件。', + 'min' => [ + 'numeric' => ':attribute 必须大于等于 :min。', + 'file' => ':attribute 大小不能小于 :min KB。', + 'string' => ':attribute 至少为 :min 个字符。', + 'array' => ':attribute 至少有 :min 个单元。', + ], + 'multiple_of' => ':attribute 必须是 :value 的倍数', + 'not_in' => '已选的属性 :attribute 非法。', + 'not_regex' => ':attribute 的格式错误。', + 'numeric' => ':attribute 必须是一个数字。', + 'password' => '密码错误。', + 'present' => ':attribute 必须存在。', + 'regex' => ':attribute 格式不正确。', + 'required' => ':attribute 不能为空。', + 'required_if' => '当 :other 为 :value 时 :attribute 不能为空。', + 'required_unless' => '当 :other 不为 :values 时 :attribute 不能为空。', + 'required_with' => '当 :values 存在时 :attribute 不能为空。', + 'required_with_all' => '当 :values 存在时 :attribute 不能为空。', + 'required_without' => '当 :values 不存在时 :attribute 不能为空。', + 'required_without_all' => '当 :values 都不存在时 :attribute 不能为空。', + 'same' => ':attribute 和 :other 必须相同。', + 'size' => [ + 'numeric' => ':attribute 大小必须为 :size。', + 'file' => ':attribute 大小必须为 :size KB。', + 'string' => ':attribute 必须是 :size 个字符。', + 'array' => ':attribute 必须为 :size 个单元。', + ], + 'starts_with' => ':attribute 必须以 :values 为开头。', + 'string' => ':attribute 必须是一个字符串。', + 'timezone' => ':attribute 必须是一个合法的时区值。', + 'unique' => ':attribute 已经存在。', + 'uploaded' => ':attribute 上传失败。', + 'url' => ':attribute 格式不正确。', + 'uuid' => ':attribute 必须是有效的 UUID。', + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => '自定义消息', + ], + ], + + 'attributes' => [], +]; diff --git a/client/components/forms/DateInput.vue b/client/components/forms/DateInput.vue index 60c801f0a..912c333c6 100644 --- a/client/components/forms/DateInput.vue +++ b/client/components/forms/DateInput.vue @@ -71,6 +71,7 @@ :max-date="maxDate" :is-dark="props.isDark" color="form-color" + :locale="props.locale" @update:model-value="updateModelValue" /> diff --git a/client/components/forms/FileInput.vue b/client/components/forms/FileInput.vue index d7e6316da..e97d809b5 100644 --- a/client/components/forms/FileInput.vue +++ b/client/components/forms/FileInput.vue @@ -50,7 +50,7 @@ >

- Uploading your file... + {{ $t('forms.fileInput.uploadingFile') }}

diff --git a/client/components/forms/FlatSelectInput.vue b/client/components/forms/FlatSelectInput.vue index 5f31962f0..83e328390 100644 --- a/client/components/forms/FlatSelectInput.vue +++ b/client/components/forms/FlatSelectInput.vue @@ -74,7 +74,7 @@ '!text-gray-500 !cursor-not-allowed' ]" > - No options available. + {{ $t('forms.select.noOptionAvailable') }} diff --git a/client/components/forms/SignatureInput.vue b/client/components/forms/SignatureInput.vue index b12baec84..7d4578dd3 100644 --- a/client/components/forms/SignatureInput.vue +++ b/client/components/forms/SignatureInput.vue @@ -25,7 +25,7 @@ >

- Uploading your file... + {{ $t('forms.fileInput.uploadingFile') }}

@@ -76,7 +76,7 @@ :class="theme.default.help" href="#" @click.prevent="openFileUpload" - >Upload file instead + >{{ $t('forms.signatureInput.uploadFileInstead') }} @@ -84,7 +84,7 @@ :class="theme.default.help" href="#" @click.prevent="clear" - >Clear + >{{ $t('forms.signatureInput.clear') }} diff --git a/client/components/forms/components/CameraUpload.vue b/client/components/forms/components/CameraUpload.vue index 9426e4f90..39184cb19 100644 --- a/client/components/forms/components/CameraUpload.vue +++ b/client/components/forms/components/CameraUpload.vue @@ -49,17 +49,16 @@ class="w-6 h-6" />

- Allow Camera Permission + {{ $t('forms.cameraUpload.allowCameraPermission') }}

- You need to allow camera permission before you can take pictures. Go to - browser settings to enable camera permission on this page. + {{ $t('forms.cameraUpload.allowCameraPermissionDescription') }}

- Got it! + {{ $t('forms.cameraUpload.gotIt') }} @@ -81,16 +80,16 @@ class="w-6 h-6" />

- Camera Device Error + {{ $t('forms.cameraUpload.cameraDeviceError') }}

- An unknown error occurred when trying to start Webcam device. + {{ $t('forms.cameraUpload.cameraDeviceErrorDescription') }}

- Go back + {{ $t('forms.cameraUpload.goBack') }} diff --git a/client/components/forms/components/VSelect.vue b/client/components/forms/components/VSelect.vue index f07149c2d..4e2def645 100644 --- a/client/components/forms/components/VSelect.vue +++ b/client/components/forms/components/VSelect.vue @@ -120,7 +120,7 @@ v-model="searchTerm" type="text" class="flex-grow ltr:pl-3 ltr:pr-7 rtl:!pr-3 rtl:pl-7 py-2 w-full focus:outline-none dark:text-white" - placeholder="Search" + :placeholder="allowCreation ? $t('forms.select.searchOrTypeToCreateNew') : $t('forms.select.search')" >
- {{ (allowCreation ? 'Type something to add an option' : 'No option available') }}. + {{ (allowCreation ? $t('forms.select.typeSomethingToAddAnOption') : $t('forms.select.noOptionAvailable')) }}.

- Create {{ + {{ $t('forms.select.create') }} {{ searchTerm }} diff --git a/client/components/forms/useFormInput.js b/client/components/forms/useFormInput.js index 3ffe97923..8bf7a289c 100644 --- a/client/components/forms/useFormInput.js +++ b/client/components/forms/useFormInput.js @@ -28,7 +28,8 @@ export const inputProps = { help: {type: String, default: null}, helpPosition: {type: String, default: "below_input"}, color: {type: String, default: "#3B82F6"}, - wrapperClass: {type: String, default: ""}, + wrapperClass: { type: String, default: "" }, + locale: { type: String, default: "en" }, } export function useFormInput(props, context, options = {}) { diff --git a/client/components/open/forms/OpenCompleteForm.vue b/client/components/open/forms/OpenCompleteForm.vue index cf4a28bfb..d80f83540 100644 --- a/client/components/open/forms/OpenCompleteForm.vue +++ b/client/components/open/forms/OpenCompleteForm.vue @@ -27,7 +27,7 @@

- This form is protected by a password. + {{ $t('forms.password_protected') }}

@@ -47,7 +47,7 @@ class="my-4" @click="passwordEntered" > - Submit + {{ $t('forms.submit') }}
@@ -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 OpnForm + {{ $t('forms.powered_by') }} {{ $t('app.name') }}

@@ -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') }}

@@ -202,7 +202,6 @@