All hardcoded strings replaced by i18n translation

This commit is contained in:
Bubka 2020-01-12 19:55:17 +01:00
parent 14e486094a
commit 11c7ff20a6
17 changed files with 380 additions and 90 deletions

View File

@ -19,29 +19,17 @@ class IconController extends Controller
*/ */
public function upload(Request $request) public function upload(Request $request)
{ {
$messages = [
'icon.image' => 'Supported format are jpeg, png, bmp, gif, svg, or webp'
];
$validator = Validator::make($request->all(), [ $validator = Validator::make($request->all(), [
'icon' => 'required|image', 'icon' => 'required|image',
], $messages); ]);
if ($validator->fails()) { if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 400); return response()->json(['error' => $validator->errors()], 400);
} }
$path = $request->file('icon')->storePublicly('public/icons');
return response()->json(pathinfo($path)['basename'], 201);
// if($request->hasFile('icon')){
$path = $request->file('icon')->storePublicly('public/icons');
return response()->json(pathinfo($path)['basename'], 201);
// }
// else
// {
// return response()->json('no file in $request', 204);
// }
} }

View File

@ -23,19 +23,14 @@ public function decode(Request $request)
{ {
// input validation // input validation
$messages = [
'qrcode.image' => 'Supported format are jpeg, png, bmp, gif, svg, or webp'
];
$validator = Validator::make($request->all(), [ $validator = Validator::make($request->all(), [
'qrcode' => 'required|image', 'qrcode' => 'required|image',
], $messages); ]);
if ($validator->fails()) { if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 400); return response()->json(['error' => $validator->errors()], 400);
} }
// qrcode analysis // qrcode analysis
$path = $request->file('qrcode')->store('qrcodes'); $path = $request->file('qrcode')->store('qrcodes');
$qrcode = new QrReader(storage_path('app/' . $path)); $qrcode = new QrReader(storage_path('app/' . $path));
@ -71,7 +66,7 @@ public function decode(Request $request)
return response()->json([ return response()->json([
'error' => [ 'error' => [
'qrcode' => 'No valid TOTP resource in this QR code' 'qrcode' => __('errors.response.no_valid_totp')
] ]
], 400); ], 400);

View File

@ -33,14 +33,11 @@ public function store(Request $request)
// see https://github.com/google/google-authenticator/wiki/Key-Uri-Format // see https://github.com/google/google-authenticator/wiki/Key-Uri-Format
// for otpauth uri format validation // for otpauth uri format validation
$messages = [
'uri.starts_with' => 'Only valid TOTP uri are supported',
];
$validator = Validator::make($request->all(), [ $validator = Validator::make($request->all(), [
'service' => 'required', 'service' => 'required',
'uri' => 'required|starts_with:otpauth://totp/', 'uri' => 'required|starts_with:otpauth://totp/',
], $messages); ]);
if ($validator->fails()) { if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 400); return response()->json(['error' => $validator->errors()], 400);
@ -69,7 +66,7 @@ public function show($id)
$twofaccount = TwoFAccount::FindOrFail($id); $twofaccount = TwoFAccount::FindOrFail($id);
return response()->json($twofaccount, 200); return response()->json($twofaccount, 200);
} catch (\Exception $e) { } catch (\Exception $e) {
return response()->json(['error'=>'not found'], 404); return response()->json( ['error' => 'not found' ], 404);
} }
} }
@ -103,7 +100,7 @@ public function update(Request $request, $id)
]); ]);
if ($validator->fails()) { if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 400); return response()->json( ['error' => $validator->errors() ], 400);
} }
@ -117,7 +114,7 @@ public function update(Request $request, $id)
} }
catch (\Exception $e) { catch (\Exception $e) {
return response()->json(['error'=>'not found'], 404); return response()->json( ['error' => 'not found' ] , 404);
} }
} }

View File

@ -17,15 +17,10 @@ class UserController extends Controller
*/ */
public function login(Request $request) public function login(Request $request)
{ {
$messages = [
'email.exists' => 'No account found using this email',
];
$validator = Validator::make($request->all(), [ $validator = Validator::make($request->all(), [
'email' => 'required|exists:users,email', 'email' => 'required|exists:users,email',
'password' => 'required', 'password' => 'required',
], $messages); ]);
if ($validator->fails()) { if ($validator->fails()) {
return response()->json(['error' => $validator->errors()], 400); return response()->json(['error' => $validator->errors()], 400);

View File

@ -5,7 +5,7 @@
<div class="column is-three-quarters-mobile is-one-third-tablet is-one-quarter-desktop is-one-quarter-widescreen is-one-quarter-fullhd"> <div class="column is-three-quarters-mobile is-one-third-tablet is-one-quarter-desktop is-one-quarter-widescreen is-one-quarter-fullhd">
<div class="field"> <div class="field">
<div class="control has-icons-right"> <div class="control has-icons-right">
<input type="text" class="input is-rounded is-search" v-model="search" placeholder=""> <input type="text" class="input is-rounded is-search" v-model="search">
<span class="icon is-small is-right"> <span class="icon is-small is-right">
<font-awesome-icon :icon="['fas', 'search']" v-if="!search" /> <font-awesome-icon :icon="['fas', 'search']" v-if="!search" />
<a class="delete" v-if="search" @click="search = '' "></a> <a class="delete" v-if="search" @click="search = '' "></a>
@ -35,9 +35,9 @@
<div class="container has-text-centered" v-show="this.showNoAccount"> <div class="container has-text-centered" v-show="this.showNoAccount">
<p class="no-account"></p> <p class="no-account"></p>
<p class="subtitle is-5 has-text-grey"> <p class="subtitle is-5 has-text-grey">
No 2FA here! {{ $t('twofaccounts.no_account_here') }}
</p> </p>
<router-link :to="{ name: 'create' }" class="button is-medium is-link is-focused">Add one</router-link> <router-link :to="{ name: 'create' }" class="button is-medium is-link is-focused">{{ $t('twofaccounts.add_one') }}</router-link>
</div> </div>
<modal v-model="ShowTwofaccountInModal"> <modal v-model="ShowTwofaccountInModal">
<twofaccount-show <twofaccount-show
@ -54,16 +54,16 @@
<div class="field is-grouped"> <div class="field is-grouped">
<p class="control"> <p class="control">
<router-link :to="{ name: 'create' }" class="button is-link is-rounded is-focus"> <router-link :to="{ name: 'create' }" class="button is-link is-rounded is-focus">
<span>New</span> <span>{{ $t('twofaccounts.new') }}</span>
<span class="icon is-small"> <span class="icon is-small">
<font-awesome-icon :icon="['fas', 'qrcode']" /> <font-awesome-icon :icon="['fas', 'qrcode']" />
</span> </span>
</router-link> </router-link>
</p> </p>
<p class="control"> <p class="control">
<a class="button is-dark is-rounded" @click="editMode = true" v-if="!editMode">Manage</a> <a class="button is-dark is-rounded" @click="editMode = true" v-if="!editMode">{{ $t('twofaccounts.manage') }}</a>
<a class="button is-success is-rounded" @click="editMode = false" v-if="editMode"> <a class="button is-success is-rounded" @click="editMode = false" v-if="editMode">
<span>Done</span> <span>{{ $t('twofaccounts.done') }}</span>
<span class="icon is-small"> <span class="icon is-small">
<font-awesome-icon :icon="['fas', 'check']" /> <font-awesome-icon :icon="['fas', 'check']" />
</span> </span>
@ -74,14 +74,14 @@
</div> </div>
<div class="content has-text-centered"> <div class="content has-text-centered">
<span v-if="token"> <span v-if="token">
Hi {{username}} ! <a class="has-text-grey" @click="logout">Sign out</a> {{ $t('auth.hello', {username: username}) }} <a class="has-text-grey" @click="logout">{{ $t('auth.sign_out') }}</a>
</span> </span>
<span v-else> <span v-else>
<router-link :to="{ name: 'login' }" class="button is-black"> <router-link :to="{ name: 'login' }" class="button is-black">
Sign in {{ $t('auth.sign_in') }}
</router-link> </router-link>
<router-link :to="{ name: 'register' }" class="button is-black"> <router-link :to="{ name: 'register' }" class="button is-black">
Register {{ $t('auth.register') }}
</router-link> </router-link>
</span> </span>
</div> </div>
@ -189,7 +189,7 @@
}, },
deleteAccount: function (id) { deleteAccount: function (id) {
if(confirm("Are you sure you want to delete this account?")) { if(confirm(this.$t('twofaccounts.confirm.delete'))) {
axios.defaults.headers.common['Content-Type'] = 'application/json' axios.defaults.headers.common['Content-Type'] = 'application/json'
axios.defaults.headers.common['Authorization'] = 'Bearer ' + this.token axios.defaults.headers.common['Authorization'] = 'Bearer ' + this.token
@ -204,7 +204,7 @@
}, },
logout(evt) { logout(evt) {
if(confirm("Are you sure you want to log out?")) { if(confirm(this.$t('auth.confirm.logout'))) {
axios.post('api/logout').then(response => { axios.post('api/logout').then(response => {
localStorage.removeItem('jwt'); localStorage.removeItem('jwt');

View File

@ -2,52 +2,52 @@
<div class="section"> <div class="section">
<div class="columns is-mobile is-centered"> <div class="columns is-mobile is-centered">
<div class="column is-two-thirds-tablet is-half-desktop is-one-third-widescreen is-one-quarter-fullhd"> <div class="column is-two-thirds-tablet is-half-desktop is-one-third-widescreen is-one-quarter-fullhd">
<h1 class="title">New account</h1> <h1 class="title">{{ $t('twofaccounts.forms.new_account') }}</h1>
<form @submit.prevent="createAccount"> <form @submit.prevent="createAccount">
<div class="field"> <div class="field">
<div class="file is-dark is-boxed"> <div class="file is-dark is-boxed">
<label class="file-label" title="Use a QR code to fill the form magically"> <label class="file-label" :title="$t('twofaccounts.forms.use_qrcode.title')">
<input class="file-input" type="file" accept="image/*" v-on:change="uploadQrcode" ref="qrcodeInput"> <input class="file-input" type="file" accept="image/*" v-on:change="uploadQrcode" ref="qrcodeInput">
<span class="file-cta"> <span class="file-cta">
<span class="file-icon"> <span class="file-icon">
<font-awesome-icon :icon="['fas', 'qrcode']" size="lg" /> <font-awesome-icon :icon="['fas', 'qrcode']" size="lg" />
</span> </span>
<span class="file-label">Use a qrcode</span> <span class="file-label">{{ $t('twofaccounts.forms.use_qrcode.val') }}</span>
</span> </span>
</label> </label>
</div> </div>
</div> </div>
<p class="help is-danger help-for-file" v-if="errors.qrcode">{{ errors.qrcode.toString() }}</p> <p class="help is-danger help-for-file" v-if="errors.qrcode">{{ errors.qrcode.toString() }}</p>
<div class="field"> <div class="field">
<label class="label">Service</label> <label class="label">{{ $t('twofaccounts.service') }}</label>
<div class="control"> <div class="control">
<input class="input" type="text" placeholder="example.com" v-model="twofaccount.service" autofocus /> <input class="input" type="text" :placeholder="$t('twofaccounts.forms.service.placeholder')" v-model="twofaccount.service" autofocus />
</div> </div>
<p class="help is-danger" v-if="errors.service">{{ errors.service.toString() }}</p> <p class="help is-danger" v-if="errors.service">{{ errors.service.toString() }}</p>
</div> </div>
<div class="field"> <div class="field">
<label class="label">Account</label> <label class="label">{{ $t('twofaccounts.account') }}</label>
<div class="control"> <div class="control">
<input class="input" type="text" placeholder="John DOE" v-model="twofaccount.account" /> <input class="input" type="text" :placeholder="$t('twofaccounts.forms.account.placeholder')" v-model="twofaccount.account" />
</div> </div>
<p class="help is-danger" v-if="errors.account">{{ errors.account.toString() }}</p> <p class="help is-danger" v-if="errors.account">{{ errors.account.toString() }}</p>
</div> </div>
<div class="field" style="margin-bottom: 0.5rem;"> <div class="field" style="margin-bottom: 0.5rem;">
<label class="label">TOTP Uri</label> <label class="label">{{ $t('twofaccounts.forms.totp_uri') }}</label>
</div> </div>
<div class="field has-addons"> <div class="field has-addons">
<div class="control is-expanded"> <div class="control is-expanded">
<input class="input" type="text" placeholder="otpauth://totp/..." v-model="twofaccount.uri" :disabled="uriIsLocked" /> <input class="input" type="text" placeholder="otpauth://totp/..." v-model="twofaccount.uri" :disabled="uriIsLocked" />
</div> </div>
<div class="control" v-if="uriIsLocked"> <div class="control" v-if="uriIsLocked">
<a class="button is-dark field-lock" @click="uriIsLocked = false" title="Unlock it (at your own risk)"> <a class="button is-dark field-lock" @click="uriIsLocked = false" :title="$t('twofaccounts.forms.unlock.title')">
<span class="icon"> <span class="icon">
<font-awesome-icon :icon="['fas', 'lock']" /> <font-awesome-icon :icon="['fas', 'lock']" />
</span> </span>
</a> </a>
</div> </div>
<div class="control" v-else> <div class="control" v-else>
<a class="button is-dark field-unlock" @click="uriIsLocked = true" title="Lock it"> <a class="button is-dark field-unlock" @click="uriIsLocked = true" :title="$t('twofaccounts.forms.lock.title')">
<span class="icon has-text-danger"> <span class="icon has-text-danger">
<font-awesome-icon :icon="['fas', 'lock-open']" /> <font-awesome-icon :icon="['fas', 'lock-open']" />
</span> </span>
@ -56,7 +56,7 @@
</div> </div>
<p class="help is-danger help-for-file" v-if="errors.uri">{{ errors.uri.toString() }}</p> <p class="help is-danger help-for-file" v-if="errors.uri">{{ errors.uri.toString() }}</p>
<div class="field"> <div class="field">
<label class="label">Icon</label> <label class="label">{{ $t('twofaccounts.icon') }}</label>
<div class="file is-dark"> <div class="file is-dark">
<label class="file-label"> <label class="file-label">
<input class="file-input" type="file" accept="image/*" v-on:change="uploadIcon" ref="iconInput"> <input class="file-input" type="file" accept="image/*" v-on:change="uploadIcon" ref="iconInput">
@ -64,7 +64,7 @@
<span class="file-icon"> <span class="file-icon">
<font-awesome-icon :icon="['fas', 'image']" /> <font-awesome-icon :icon="['fas', 'image']" />
</span> </span>
<span class="file-label">Choose an image</span> <span class="file-label">{{ $t('twofaccounts.forms.choose_image') }}</span>
</span> </span>
</label> </label>
<span class="tag is-black is-large" v-if="tempIcon"> <span class="tag is-black is-large" v-if="tempIcon">
@ -76,10 +76,10 @@
<p class="help is-danger help-for-file" v-if="errors.icon">{{ errors.icon.toString() }}</p> <p class="help is-danger help-for-file" v-if="errors.icon">{{ errors.icon.toString() }}</p>
<div class="field is-grouped"> <div class="field is-grouped">
<div class="control"> <div class="control">
<button type="submit" class="button is-link">Create</button> <button type="submit" class="button is-link">{{ $t('twofaccounts.forms.create') }}</button>
</div> </div>
<div class="control"> <div class="control">
<button class="button is-text" @click="cancelCreation">Cancel</button> <button class="button is-text" @click="cancelCreation">{{ $t('commons.cancel') }}</button>
</div> </div>
</div> </div>
</form> </form>

View File

@ -2,24 +2,24 @@
<div class="section" v-if="twofaccountExists"> <div class="section" v-if="twofaccountExists">
<div class="columns is-mobile is-centered"> <div class="columns is-mobile is-centered">
<div class="column is-two-thirds-tablet is-half-desktop is-one-third-widescreen is-one-quarter-fullhd"> <div class="column is-two-thirds-tablet is-half-desktop is-one-third-widescreen is-one-quarter-fullhd">
<h1 class="title">Edit account</h1> <h1 class="title">{{ $t('twofaccounts.forms.edit_account') }}</h1>
<form @submit.prevent="updateAccount"> <form @submit.prevent="updateAccount">
<div class="field"> <div class="field">
<label class="label">Service</label> <label class="label">{{ $t('twofaccounts.service') }}</label>
<div class="control"> <div class="control">
<input class="input" type="text" placeholder="example.com" v-model="twofaccount.service" autofocus /> <input class="input" type="text" :placeholder="$t('twofaccounts.forms.service.placeholder')" v-model="twofaccount.service" autofocus />
</div> </div>
<p class="help is-danger" v-if="errors.service">{{ errors.service.toString() }}</p> <p class="help is-danger" v-if="errors.service">{{ errors.service.toString() }}</p>
</div> </div>
<div class="field"> <div class="field">
<label class="label">Account</label> <label class="label">{{ $t('twofaccounts.account') }}</label>
<div class="control"> <div class="control">
<input class="input" type="text" placeholder="John DOE" v-model="twofaccount.account" /> <input class="input" type="text" :placeholder="$t('twofaccounts.forms.account.placeholder')" v-model="twofaccount.account" />
</div> </div>
<p class="help is-danger" v-if="errors.account">{{ errors.account.toString() }}</p> <p class="help is-danger" v-if="errors.account">{{ errors.account.toString() }}</p>
</div> </div>
<div class="field"> <div class="field">
<label class="label">Icon</label> <label class="label">{{ $t('twofaccounts.icon') }}</label>
<div class="file is-dark"> <div class="file is-dark">
<label class="file-label"> <label class="file-label">
<input class="file-input" type="file" accept="image/*" v-on:change="uploadIcon" ref="iconInput"> <input class="file-input" type="file" accept="image/*" v-on:change="uploadIcon" ref="iconInput">
@ -27,7 +27,7 @@
<span class="file-icon"> <span class="file-icon">
<font-awesome-icon :icon="['fas', 'image']" /> <font-awesome-icon :icon="['fas', 'image']" />
</span> </span>
<span class="file-label">Choose an image</span> <span class="file-label">{{ $t('twofaccounts.forms.choose_image') }}</span>
</span> </span>
</label> </label>
<span class="tag is-black is-large" v-if="tempIcon"> <span class="tag is-black is-large" v-if="tempIcon">
@ -39,10 +39,10 @@
<p class="help is-danger help-for-file" v-if="errors.icon">{{ errors.icon.toString() }}</p> <p class="help is-danger help-for-file" v-if="errors.icon">{{ errors.icon.toString() }}</p>
<div class="field is-grouped"> <div class="field is-grouped">
<div class="control"> <div class="control">
<button type="submit" class="button is-link">Save</button> <button type="submit" class="button is-link">{{ $t('twofaccounts.forms.save') }}</button>
</div> </div>
<div class="control"> <div class="control">
<button class="button is-text" @click.prevent="cancelCreation">Cancel</button> <button class="button is-text" @click.prevent="cancelCreation">{{ $t('commons.cancel') }}</button>
</div> </div>
</div> </div>
</form> </form>

View File

@ -3,11 +3,11 @@
<modal v-model="ShowModal"> <modal v-model="ShowModal">
<div v-if="$route.name == '404'"> <div v-if="$route.name == '404'">
<p class="error-404"></p> <p class="error-404"></p>
<p>Resource not found, please <router-link :to="{ name: 'accounts' }" class="is-text has-text-white">refresh</router-link></p> <p>{{ $t('errors.resource_not_found') }}<router-link :to="{ name: 'accounts' }" class="is-text has-text-white">{{ $t('errors.refresh') }}</router-link></p>
</div> </div>
<div v-else> <div v-else>
<p class="error-generic"></p> <p class="error-generic"></p>
<p>An error occured, please <router-link :to="{ name: 'accounts' }" class="is-text has-text-white">refresh</router-link></p> <p>{{ $t('errors.error_occured') }}<router-link :to="{ name: 'accounts' }" class="is-text has-text-white">{{ $t('errors.refresh') }}</router-link></p>
</div> </div>
<div v-if="debugMode == 'development'"> <div v-if="debugMode == 'development'">
<p v-if="debug" class="debug"> <p v-if="debug" class="debug">

View File

@ -2,17 +2,17 @@
<div class="section"> <div class="section">
<div class="columns is-mobile is-centered"> <div class="columns is-mobile is-centered">
<div class="column is-two-thirds-tablet is-half-desktop is-one-third-widescreen is-one-quarter-fullhd"> <div class="column is-two-thirds-tablet is-half-desktop is-one-third-widescreen is-one-quarter-fullhd">
<h1 class="title">Login</h1> <h1 class="title">{{ $t('auth.forms.login') }}</h1>
<form method="POST" action="/login"> <form method="POST" action="/login">
<div class="field"> <div class="field">
<label class="label">Email</label> <label class="label">{{ $t('auth.forms.email') }}</label>
<div class="control"> <div class="control">
<input id="email" type="email" class="input" v-model="email" required autofocus /> <input id="email" type="email" class="input" v-model="email" required autofocus />
</div> </div>
<p class="help is-danger" v-if="errors.email">{{ errors.email.toString() }}</p> <p class="help is-danger" v-if="errors.email">{{ errors.email.toString() }}</p>
</div> </div>
<div class="field"> <div class="field">
<label class="label">Password</label> <label class="label">{{ $t('auth.forms.password') }}</label>
<div class="control"> <div class="control">
<input id="password" type="password" class="input" v-model="password" required /> <input id="password" type="password" class="input" v-model="password" required />
</div> </div>
@ -20,7 +20,7 @@
</div> </div>
<div class="field"> <div class="field">
<div class="control"> <div class="control">
<button type="submit" class="button is-link" @click="handleSubmit">Sign in</button> <button type="submit" class="button is-link" @click="handleSubmit">{{ $t('auth.sign_in') }}</button>
</div> </div>
</div> </div>
</form> </form>
@ -28,8 +28,8 @@
</div> </div>
<div class="columns is-mobile is-centered"> <div class="columns is-mobile is-centered">
<div class="column is-two-thirds-tablet is-half-desktop is-one-third-widescreen is-one-quarter-fullhd"> <div class="column is-two-thirds-tablet is-half-desktop is-one-third-widescreen is-one-quarter-fullhd">
Don't have an account yet? <router-link :to="{ name: 'register' }" class="is-link"> {{ $t('auth.forms.dont_have_account_yet') }}&nbsp;<router-link :to="{ name: 'register' }" class="is-link">
Register {{ $t('auth.register') }}
</router-link> </router-link>
</div> </div>
</div> </div>
@ -66,7 +66,7 @@
this.errors = error.response.data.error this.errors = error.response.data.error
} }
else { else {
this.errors['password'] = [ 'Password do not match' ] this.errors['password'] = [ this.$t('auth.forms.passwords_do_not_match') ]
} }
}); });
} }

View File

@ -2,31 +2,31 @@
<div class="section"> <div class="section">
<div class="columns is-mobile is-centered"> <div class="columns is-mobile is-centered">
<div class="column is-two-thirds-tablet is-half-desktop is-one-third-widescreen is-one-quarter-fullhd"> <div class="column is-two-thirds-tablet is-half-desktop is-one-third-widescreen is-one-quarter-fullhd">
<h1 class="title">Register</h1> <h1 class="title">{{ $t('auth.register') }}</h1>
<form method="POST" action="/register"> <form method="POST" action="/register">
<div class="field"> <div class="field">
<label class="label">Name</label> <label class="label">{{ $t('auth.forms.name') }}</label>
<div class="control"> <div class="control">
<input id="name" type="text" class="input" v-model="name" required autofocus /> <input id="name" type="text" class="input" v-model="name" required autofocus />
</div> </div>
<p class="help is-danger" v-if="errors.name">{{ errors.name.toString() }}</p> <p class="help is-danger" v-if="errors.name">{{ errors.name.toString() }}</p>
</div> </div>
<div class="field"> <div class="field">
<label class="label">Email</label> <label class="label">{{ $t('auth.forms.email') }}</label>
<div class="control"> <div class="control">
<input id="email" type="email" class="input" v-model="email" required /> <input id="email" type="email" class="input" v-model="email" required />
</div> </div>
<p class="help is-danger" v-if="errors.email">{{ errors.email.toString() }}</p> <p class="help is-danger" v-if="errors.email">{{ errors.email.toString() }}</p>
</div> </div>
<div class="field"> <div class="field">
<label class="label">Password</label> <label class="label">{{ $t('auth.forms.password') }}</label>
<div class="control"> <div class="control">
<input id="password" type="password" class="input" v-model="password" required /> <input id="password" type="password" class="input" v-model="password" required />
</div> </div>
<p class="help is-danger" v-if="errors.password">{{ errors.password.toString() }}</p> <p class="help is-danger" v-if="errors.password">{{ errors.password.toString() }}</p>
</div> </div>
<div class="field"> <div class="field">
<label class="label">Confirm Password</label> <label class="label">{{ $t('auth.forms.confirm_password') }}</label>
<div class="control"> <div class="control">
<input id="password_confirmation" type="password" class="input" v-model="password_confirmation" required /> <input id="password_confirmation" type="password" class="input" v-model="password_confirmation" required />
</div> </div>
@ -34,7 +34,7 @@
</div> </div>
<div class="field"> <div class="field">
<div class="control"> <div class="control">
<button type="submit" class="button is-link" @click="handleSubmit">Register</button> <button type="submit" class="button is-link" @click="handleSubmit">{{ $t('auth.register') }}</button>
</div> </div>
</div> </div>
</form> </form>
@ -42,8 +42,8 @@
</div> </div>
<div class="columns is-mobile is-centered"> <div class="columns is-mobile is-centered">
<div class="column is-two-thirds-tablet is-half-desktop is-one-third-widescreen is-one-quarter-fullhd"> <div class="column is-two-thirds-tablet is-half-desktop is-one-third-widescreen is-one-quarter-fullhd">
Already registered? <router-link :to="{ name: 'login' }" class="is-link"> {{ $t('auth.forms.already_register') }}&nbsp;<router-link :to="{ name: 'login' }" class="is-link">
Sign in {{ $t('auth.sign_in') }}
</router-link> </router-link>
</div> </div>
</div> </div>

View File

@ -0,0 +1,192 @@
export default {
"en": {
"auth": {
"sign_out": "Sign out",
"sign_in": "Sign in",
"register": "Register",
"hello": "Hi {username} !",
"confirm": {
"logout": "Are you sure you want to log out?"
},
"forms": {
"name": "Name",
"login": "Login",
"email": "Email",
"password": "Password",
"confirm_password": "Confirm password",
"dont_have_account_yet": "Don't have an account yet?",
"already_register": "Already registered?",
"passwords_do_not_match": "Passwords do not match"
}
},
"commons": {
"cancel": "Cancel"
},
"errors": {
"resource_not_found": "Resource not found, please ",
"error_occured": "An error occured, please ",
"refresh": "refresh"
},
"pagination": {
"previous": "&laquo; Previous",
"next": "Next &raquo;"
},
"passwords": {
"password": "Passwords must be at least eight characters and match the confirmation.",
"reset": "Your password has been reset!",
"sent": "We have e-mailed your password reset link!",
"token": "This password reset token is invalid.",
"user": "We can't find a user with that e-mail address."
},
"twofaccounts": {
"service": "Service",
"account": "Account",
"icon": "Icon",
"new": "New",
"no_account_here": "No 2FA here!",
"add_one": "Add one",
"manage": "Manage",
"done": "Done",
"forms": {
"service": {
"placeholder": "example.com"
},
"account": {
"placeholder": "John DOE"
},
"new_account": "New account",
"edit_account": "Edit account",
"totp_uri": "TOTP Uri",
"use_qrcode": {
"val": "Use a qrcode",
"title": "Use a QR code to fill the form magically"
},
"unlock": {
"val": "Unlock",
"title": "Unlock it (at your own risk)"
},
"lock": {
"val": "Lock",
"title": "Lock it"
},
"choose_image": "Choose an image…",
"create": "Create",
"save": "Save"
},
"confirm": {
"delete": "Are you sure you want to delete this account?"
}
},
"validation": {
"accepted": "The {attribute} must be accepted.",
"active_url": "The {attribute} is not a valid URL.",
"after": "The {attribute} must be a date after {date}.",
"after_or_equal": "The {attribute} must be a date after or equal to {date}.",
"alpha": "The {attribute} may only contain letters.",
"alpha_dash": "The {attribute} may only contain letters, numbers, dashes and underscores.",
"alpha_num": "The {attribute} may only contain letters and numbers.",
"array": "The {attribute} must be an array.",
"before": "The {attribute} must be a date before {date}.",
"before_or_equal": "The {attribute} must be a date before or equal to {date}.",
"between": {
"numeric": "The {attribute} must be between {min} and {max}.",
"file": "The {attribute} must be between {min} and {max} kilobytes.",
"string": "The {attribute} must be between {min} and {max} characters.",
"array": "The {attribute} must have between {min} and {max} items."
},
"boolean": "The {attribute} field must be true or false.",
"confirmed": "The {attribute} confirmation does not match.",
"date": "The {attribute} is not a valid date.",
"date_equals": "The {attribute} must be a date equal to {date}.",
"date_format": "The {attribute} does not match the format {format}.",
"different": "The {attribute} and {other} must be different.",
"digits": "The {attribute} must be {digits} digits.",
"digits_between": "The {attribute} must be between {min} and {max} digits.",
"dimensions": "The {attribute} has invalid image dimensions.",
"distinct": "The {attribute} field has a duplicate value.",
"email": "The {attribute} must be a valid email address.",
"ends_with": "The {attribute} must end with one of the following: {values}",
"exists": "The selected {attribute} is invalid.",
"file": "The {attribute} must be a file.",
"filled": "The {attribute} field must have a value.",
"gt": {
"numeric": "The {attribute} must be greater than {value}.",
"file": "The {attribute} must be greater than {value} kilobytes.",
"string": "The {attribute} must be greater than {value} characters.",
"array": "The {attribute} must have more than {value} items."
},
"gte": {
"numeric": "The {attribute} must be greater than or equal {value}.",
"file": "The {attribute} must be greater than or equal {value} kilobytes.",
"string": "The {attribute} must be greater than or equal {value} characters.",
"array": "The {attribute} must have {value} items or more."
},
"image": "The {attribute} must be an image.",
"in": "The selected {attribute} is invalid.",
"in_array": "The {attribute} field does not exist in {other}.",
"integer": "The {attribute} must be an integer.",
"ip": "The {attribute} must be a valid IP address.",
"ipv4": "The {attribute} must be a valid IPv4 address.",
"ipv6": "The {attribute} must be a valid IPv6 address.",
"json": "The {attribute} must be a valid JSON string.",
"lt": {
"numeric": "The {attribute} must be less than {value}.",
"file": "The {attribute} must be less than {value} kilobytes.",
"string": "The {attribute} must be less than {value} characters.",
"array": "The {attribute} must have less than {value} items."
},
"lte": {
"numeric": "The {attribute} must be less than or equal {value}.",
"file": "The {attribute} must be less than or equal {value} kilobytes.",
"string": "The {attribute} must be less than or equal {value} characters.",
"array": "The {attribute} must not have more than {value} items."
},
"max": {
"numeric": "The {attribute} may not be greater than {max}.",
"file": "The {attribute} may not be greater than {max} kilobytes.",
"string": "The {attribute} may not be greater than {max} characters.",
"array": "The {attribute} may not have more than {max} items."
},
"mimes": "The {attribute} must be a file of type: {values}.",
"mimetypes": "The {attribute} must be a file of type: {values}.",
"min": {
"numeric": "The {attribute} must be at least {min}.",
"file": "The {attribute} must be at least {min} kilobytes.",
"string": "The {attribute} must be at least {min} characters.",
"array": "The {attribute} must have at least {min} items."
},
"not_in": "The selected {attribute} is invalid.",
"not_regex": "The {attribute} format is invalid.",
"numeric": "The {attribute} must be a number.",
"present": "The {attribute} field must be present.",
"regex": "The {attribute} format is invalid.",
"required": "The {attribute} field is required.",
"required_if": "The {attribute} field is required when {other} is {value}.",
"required_unless": "The {attribute} field is required unless {other} is in {values}.",
"required_with": "The {attribute} field is required when {values} is present.",
"required_with_all": "The {attribute} field is required when {values} are present.",
"required_without": "The {attribute} field is required when {values} is not present.",
"required_without_all": "The {attribute} field is required when none of {values} are present.",
"same": "The {attribute} and {other} must match.",
"size": {
"numeric": "The {attribute} must be {size}.",
"file": "The {attribute} must be {size} kilobytes.",
"string": "The {attribute} must be {size} characters.",
"array": "The {attribute} must contain {size} items."
},
"starts_with": "The {attribute} must start with one of the following: {values}",
"string": "The {attribute} must be a string.",
"timezone": "The {attribute} must be a valid zone.",
"unique": "The {attribute} has already been taken.",
"uploaded": "The {attribute} failed to upload.",
"url": "The {attribute} format is invalid.",
"uuid": "The {attribute} must be a valid UUID.",
"custom": {
"attribute-name": {
"rule-name": "custom-message"
}
},
"attributes": []
}
}
}

View File

@ -13,7 +13,23 @@
| |
*/ */
'failed' => 'These credentials do not match our records.', 'sign_out' => 'Sign out',
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', 'sign_in' => 'Sign in',
'register' => 'Register',
'hello' => 'Hi {username} !',
'confirm' => [
'logout' => 'Are you sure you want to log out?',
],
'forms' => [
'name' => 'Name',
'login' => 'Login',
'email' => 'Email',
'password' => 'Password',
'confirm_password' => 'Confirm password',
'dont_have_account_yet' => 'Don\'t have an account yet?',
'already_register' => 'Already registered?',
'passwords_do_not_match' => 'Passwords do not match',
]
]; ];

View File

@ -0,0 +1,18 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used during authentication for various
| messages that we need to display to the user. You are free to modify
| these language lines according to your application's requirements.
|
*/
'cancel' => 'Cancel',
];

View File

@ -0,0 +1,23 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used during authentication for various
| messages that we need to display to the user. You are free to modify
| these language lines according to your application's requirements.
|
*/
'resource_not_found' => 'Resource not found, please ',
'error_occured' => 'An error occured, please ',
'refresh' => 'refresh',
'response' => [
'no_valid_totp' => 'No valid TOTP resource in this QR code',
]
];

View File

@ -0,0 +1,54 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used during authentication for various
| messages that we need to display to the user. You are free to modify
| these language lines according to your application's requirements.
|
*/
'service' => 'Service',
'account' => 'Account',
'icon' => 'Icon',
'new' => 'New',
'no_account_here' => 'No 2FA here!',
'add_one' => 'Add one',
'manage' => 'Manage',
'done' => 'Done',
'forms' => [
'service' => [
'placeholder' => 'example.com',
],
'account' => [
'placeholder' => 'John DOE',
],
'new_account' => 'New account',
'edit_account' => 'Edit account',
'totp_uri' => 'TOTP Uri',
'use_qrcode' => [
'val' => 'Use a qrcode',
'title' => 'Use a QR code to fill the form magically',
],
'unlock' => [
'val' => 'Unlock',
'title' => 'Unlock it (at your own risk)',
],
'lock' => [
'val' => 'Lock',
'title' => 'Lock it',
],
'choose_image' => 'Choose an image…',
'create' => 'Create',
'save' => 'Save',
],
'confirm' => [
'delete' => 'Are you sure you want to delete this account?',
],
];

View File

@ -132,6 +132,18 @@
'attribute-name' => [ 'attribute-name' => [
'rule-name' => 'custom-message', 'rule-name' => 'custom-message',
], ],
'icon' => [
'image' => 'Supported format are jpeg, png, bmp, gif, svg, or webp',
],
'qrcode' => [
'image' => 'Supported format are jpeg, png, bmp, gif, svg, or webp',
],
'uri' => [
'starts_with' => 'Only valid TOTP uri are supported',
],
'email' => [
'exists' => 'No account found using this email',
]
], ],
/* /*

View File

@ -14,6 +14,6 @@
</div> </div>
<script src="{{ mix('js/bootstrap.js') }}"></script> <script src="{{ mix('js/bootstrap.js') }}"></script>
<script src="{{ mix('js/app.js') }}"></script> <script src="{{ mix('js/app.js') }}"></script>
<script src="{{ asset('js/vue-i18n-locales.generated.js') }}"></script> <script src="{{ mix('js/vue-i18n-locales.generated.js') }}"></script>
</body> </body>
</html> </html>