More translations

This commit is contained in:
garrettmills 2020-06-01 19:43:29 -05:00
parent c956628c53
commit 0bec18825e
No known key found for this signature in database
GPG Key ID: 6ACD58D6ADACFC6E
8 changed files with 129 additions and 45 deletions

View File

@ -8,41 +8,34 @@ const template = `
<div class="coreid-header font-weight-light">{{ app_name }}</div> <div class="coreid-header font-weight-light">{{ app_name }}</div>
<span v-if="step === 0"> <span v-if="step === 0">
<div class="coreid-message"> <div class="coreid-message">
We're going to walk you through setting up multi-factor authentication for your account. <span v-if="t['mfa.setup_prompt']" v-html="t['mfa.setup_prompt'].replace('APP_NAME', app_name)"></span>
<br><br>
Once this is completed, you will need to provide your second factor of authentication whenever you sign in with your {{ app_name }} account.
<br><br>
You'll need some kind of MFA token generator such as Google Authenticator.
</div> </div>
<div class="buttons text-right pad-top"> <div class="buttons text-right pad-top">
<button type="button" class="btn btn-primary" @click="back_click">Cancel</button> <button type="button" class="btn btn-primary" @click="back_click">{{ t['common.cancel'] }}</button>
<button type="button" class="btn btn-primary" @click="continue_click">Continue</button> <button type="button" class="btn btn-primary" @click="continue_click">{{ t['common.continue'] }}</button>
</div> </div>
</span> </span>
<span v-if="step === 1"> <span v-if="step === 1">
<div class="coreid-message"> <div class="coreid-message">
Scan the QR code below with your authenticator app to add your {{ app_name }} account. <span v-if="t['mfa.setup_qr_prompt']" v-html="t['mfa.setup_qr_prompt'].replace('APP_NAME', app_name)"></span>
<br><br>
Once you've done this, we'll ask for one of the generated codes to verify that MFA is working correctly.
</div> </div>
<div class="coreid-auth-image text-center"> <div class="coreid-auth-image text-center">
<img class="img-fluid" :src="qr_data"> <img class="img-fluid" :src="qr_data">
<br><br><small>Secret: {{ secret }}</small> <br><br><small>{{ t['mfa.secret'] }} {{ secret }}</small>
</div> </div>
<div class="buttons text-right pad-top"> <div class="buttons text-right pad-top">
<button class="btn btn-primary" type="button" @click="continue_click">Continue</button> <button class="btn btn-primary" type="button" @click="continue_click">{{ t['common.continue'] }}</button>
</div> </div>
</span> </span>
<span v-if="step === 2"> <span v-if="step === 2">
<div class="coreid-message"> <div class="coreid-message" v-if="t['mfa.setup_success']">
Now, enter the code displayed in your authenticator app. {{ app_name }} will verify that the code is {{ t['mfa.setup_success'].replace('APP_NAME', app_name) }}
correct. Then, you can enable MFA for your account.
</div> </div>
<div class="form-group"> <div class="form-group">
<input <input
class="form-control" class="form-control"
type="number" type="number"
placeholder="2FA Code" :placeholder="t['mfa.mfa_code']"
v-model="verify_code" v-model="verify_code"
@keyup="on_key_up" @keyup="on_key_up"
name="verify_code" name="verify_code"
@ -54,8 +47,8 @@ const template = `
<div v-if="error_message" class="error-message">{{ error_message }}</div> <div v-if="error_message" class="error-message">{{ error_message }}</div>
<div v-if="other_message" class="other-message">{{ other_message }}</div> <div v-if="other_message" class="other-message">{{ other_message }}</div>
<div class="buttons text-right pad-top"> <div class="buttons text-right pad-top">
<button class="btn btn-primary" type="button" @click="back_click">Back</button> <button class="btn btn-primary" type="button" @click="back_click">{{ t['common.back'] }}</button>
<button class="btn btn-primary" type="button" @click="continue_click" :disabled="!verify_success">Enable 2FA</button> <button class="btn btn-primary" type="button" @click="continue_click" :disabled="!verify_success">{{ t['mfa.enable_mfa'] }}</button>
</div> </div>
</span> </span>
<div class="coreid-loading-spinner" v-if="loading"><div class="inner"></div></div> <div class="coreid-loading-spinner" v-if="loading"><div class="inner"></div></div>
@ -80,6 +73,25 @@ export default class MFASetupPage extends Component {
error_message = '' error_message = ''
other_message = '' other_message = ''
t = {}
async vue_on_create() {
this.t = await T(
'mfa.setup_prompt',
'common.cancel',
'common.continue',
'mfa.setup_qr_prompt',
'mfa.secret',
'mfa.setup_success',
'mfa.mfa_code',
'common.back',
'mfa.enable_mfa',
'mfa.invalid_code',
'mfa.setup_code_success',
'mfa.mfa_enabled',
'common.unknown_error'
)
}
async watch_verify_code(new_verify_code, old_verify_code) { async watch_verify_code(new_verify_code, old_verify_code) {
if ( new_verify_code.length === 6 ) { if ( new_verify_code.length === 6 ) {
@ -89,10 +101,10 @@ export default class MFASetupPage extends Component {
this.loading = false this.loading = false
if ( !this.verify_success ) { if ( !this.verify_success ) {
this.other_message = '' this.other_message = ''
this.error_message = `Uh, oh! It looks like that's not the right code. Please try again.` this.error_message = this.t['mfa.invalid_code']
} else { } else {
this.error_message = '' this.error_message = ''
this.other_message = `Success! That code matched what ${this.app_name} was expecting. You can now enable multi-factor authentication for your account.` this.other_message = this.t['mfa.setup_code_success'].replace('APP_NAME', this.app_name)
} }
} else if ( new_verify_code.length > 6 ) { } else if ( new_verify_code.length > 6 ) {
this.verify_code = old_verify_code this.verify_code = old_verify_code
@ -136,11 +148,11 @@ export default class MFASetupPage extends Component {
try { try {
await auth_api.mfa_enable() await auth_api.mfa_enable()
this.error_message = '' this.error_message = ''
this.other_message = 'MFA has been enabled for your account! For security purposes, you will be asked to sign in again.' this.other_message = this.t['mfa.mfa_enabled']
await location_service.redirect('/auth/login', 3000) await location_service.redirect('/auth/login', 3000)
} catch(e) { } catch(e) {
this.loading = false this.loading = false
this.error_message = 'Sorry, an unknown error occurred, and we were unable to continue.' this.error_message = this.t['common.unknown_error']
this.other_message = '' this.other_message = ''
} }
} }

View File

@ -1,5 +1,4 @@
import { Component } from '../../lib/vues6/vues6.js' import { Component } from '../../lib/vues6/vues6.js'
import { auth_api } from '../service/AuthApi.service.js'
import { action_service } from '../service/Action.service.js' import { action_service } from '../service/Action.service.js'
const template = ` const template = `

View File

@ -5,25 +5,25 @@ import { password_service } from '../service/Password.service.js'
const template = ` const template = `
<div class="coreid-auth-page col-lg-6 col-md-8 col-sm-10 col-xs-12 offset-lg-3 offset-md-2 offset-sm-1 offset-xs-0 text-left"> <div class="coreid-auth-page col-lg-6 col-md-8 col-sm-10 col-xs-12 offset-lg-3 offset-md-2 offset-sm-1 offset-xs-0 text-left">
<div class="coreid-auth-page-inner"> <div v-if="ready" class="coreid-auth-page-inner">
<div class="coreid-header font-weight-light">{{ app_name }}</div> <div class="coreid-header font-weight-light">{{ app_name }}</div>
<span v-if="step === 0"> <span v-if="step === 0">
<div class="coreid-message"> <div class="coreid-message">
We're going to walk you through resetting your {{ app_name }} password. {{ t['password.reset_prompt'].replace('APP_NAME', app_name) }}
<span v-if="has_mfa"> <span v-if="has_mfa">
<br><br> <br><br>
Note that this process will invalidate any existing app passwords you have created. {{ t['password.reset_invalidates'] }}
</span> </span>
</div> </div>
</span> </span>
<span v-if="step === 1"> <span v-if="step === 1">
<div class="form-group"> <div class="form-group">
<label for="coreid-password-reset-input-step-1">Please enter a new password for your account:</label> <label for="coreid-password-reset-input-step-1">{{ t['password.enter_new_pw'] }}</label>
<input <input
id="coreid-password-reset-input-step-1" id="coreid-password-reset-input-step-1"
type="password" type="password"
v-model="password" v-model="password"
placeholder="New password" :placeholder="t['password.new_password']"
class="form-control" class="form-control"
@keyup="on_key_up" @keyup="on_key_up"
:disabled="loading" :disabled="loading"
@ -32,18 +32,18 @@ const template = `
> >
</div> </div>
<div> <div>
<div class="other-message" v-if="step_1_calc_time">This password would take {{ step_1_calc_time }} to crack.</div> <div class="other-message" v-if="step_1_calc_time">{{ t['password.calc_time'].replace('CALC_TIME', step_1_calc_time) }}</div>
<div class="error-message" v-if="step_1_problem">{{ step_1_problem }}.</div> <div class="error-message" v-if="step_1_problem">{{ step_1_problem }}.</div>
</div> </div>
</span> </span>
<span v-if="step === 2"> <span v-if="step === 2">
<div class="form-group"> <div class="form-group">
<label for="coreid-password-reset-input-step-1">Confirm the password:</label> <label for="coreid-password-reset-input-step-1">{{ t['password.confirm'] }}</label>
<input <input
id="coreid-password-reset-input-step-2" id="coreid-password-reset-input-step-2"
type="password" type="password"
v-model="confirm_password" v-model="confirm_password"
placeholder="Confirm new password" :placeholder="t['password.confirm_password']"
class="form-control" class="form-control"
@keyup="on_key_up" @keyup="on_key_up"
:disabled="loading" :disabled="loading"
@ -60,13 +60,13 @@ const template = `
class="btn btn-primary" class="btn btn-primary"
@click="back_click" @click="back_click"
:disabled="loading" :disabled="loading"
>Cancel</button> >{{ t['common.cancel'] }}</button>
<button <button
type="button" type="button"
class="btn btn-primary" class="btn btn-primary"
@click="continue_click" @click="continue_click"
:disabled="loading || (step === 1 && !step_1_valid) || (step === 2 && !step_2_valid)" :disabled="loading || (step === 1 && !step_1_valid) || (step === 2 && !step_2_valid)"
>{{ step === 2 ? 'Change Password' : 'Continue' }}</button> >{{ step === 2 ? t['password.change'] : t['common.continue'] }}</button>
</div> </div>
<div class="coreid-loading-spinner" v-if="loading"><div class="inner"></div></div> <div class="coreid-loading-spinner" v-if="loading"><div class="inner"></div></div>
</div> </div>
@ -93,9 +93,28 @@ export default class PasswordResetComponent extends Component {
password = '' password = ''
confirm_password = '' confirm_password = ''
t = {}
ready = false
vue_on_create() { async vue_on_create() {
this.has_mfa = !!session.get('user.has_mfa') this.has_mfa = !!session.get('user.has_mfa')
this.t = await T(
'password.reset_prompt',
'password.reset_invalidates',
'password.enter_new_pw',
'password.calc_time',
'password.confirm',
'password.new_password',
'password.confirm_password',
'password.change',
'password.reset_success',
'common.unknown_error',
'common.continue',
'common.cancel'
)
this.ready = true
} }
async back_click() { async back_click() {
@ -131,10 +150,10 @@ export default class PasswordResetComponent extends Component {
if ( this.step_2_valid ) { if ( this.step_2_valid ) {
try { try {
await password_service.reset(this.password) await password_service.reset(this.password)
this.other_message = 'Your password was reset. For security reasons, you will be asked to sign-in again.' this.other_message = this.t['password.reset_success']
await location_service.redirect('/dash/profile', 5000) await location_service.redirect('/dash/profile', 5000)
} catch (e) { } catch (e) {
let message = 'An unknown error occurred while attempting to reset your password.' let message = this.t['common.unknown_error']
if ( e.response && e.response.data && e.response.data.message ) { if ( e.response && e.response.data && e.response.data.message ) {
message = e.response.data.message message = e.response.data.message
} }

View File

@ -19,7 +19,7 @@ const template = `
</h3> </h3>
<div class="row" v-if="!is_ready"> <div class="row" v-if="!is_ready">
<div class="col-12 text-center pad-top mb-5"> <div class="col-12 text-center pad-top mb-5">
<h4>Loading...</h4> <h4>{{ t['common.loading'] }}...</h4>
</div> </div>
</div> </div>
<form v-on:submit.prevent="do_nothing" v-if="is_ready"> <form v-on:submit.prevent="do_nothing" v-if="is_ready">
@ -106,7 +106,7 @@ const template = `
:id="uuid+field.field+'-confirm'" :id="uuid+field.field+'-confirm'"
v-model="data[field.field+'-confirm']" v-model="data[field.field+'-confirm']"
:required="Array.isArray(field.required) ? field.required.includes(mode) : field.required" :required="Array.isArray(field.required) ? field.required.includes(mode) : field.required"
:placeholder="'Confirm ' + field.name" :placeholder="t['common.confirm'] + ' ' + field.name"
:readonly="mode === 'view' || (Array.isArray(field.readonly) ? field.readonly.includes(mode) : field.readonly)" :readonly="mode === 'view' || (Array.isArray(field.readonly) ? field.readonly.includes(mode) : field.readonly)"
> >
<small class="form-text" style="color: darkred;" v-if="field.error">{{ field.error }}</small> <small class="form-text" style="color: darkred;" v-if="field.error">{{ field.error }}</small>
@ -121,7 +121,7 @@ const template = `
type="button" type="button"
v-if="mode !== 'view'" v-if="mode !== 'view'"
@click="save_click" @click="save_click"
>Save</button> >{{ t['common.save'] }}</button>
</div> </div>
</span> </span>
</div> </div>
@ -159,6 +159,7 @@ export default class FormComponent extends Component {
is_ready = false is_ready = false
mode = '' mode = ''
id = '' id = ''
t = {}
reset() { reset() {
this.definition = {} this.definition = {}
@ -171,6 +172,18 @@ export default class FormComponent extends Component {
} }
async vue_on_create(internal = false) { async vue_on_create(internal = false) {
this.t = await T(
'common.loading',
'common.confirm',
'common.save',
'common.not_permission',
'common.item_saved',
'common.unknown_error',
'common.field_required',
'common.confirmation_not_match',
'common.invalid_json'
)
if ( !internal ) { if ( !internal ) {
this.mode = this.initial_mode this.mode = this.initial_mode
this.id = this.form_id this.id = this.form_id
@ -181,7 +194,7 @@ export default class FormComponent extends Component {
this.access_msg = true this.access_msg = true
} else { } else {
this.can_access = false this.can_access = false
this.access_msg = 'Sorry, you do not have permission to ' + this.mode + ' this resource.' this.access_msg = this.t['common.not_permission'].replace('ACTION', this.mode)
return return
} }
@ -283,12 +296,12 @@ export default class FormComponent extends Component {
} }
this.error_message = '' this.error_message = ''
this.other_message = `The ${this.resource_class.item} was saved.` this.other_message = this.t['common.item_saved'].replace('ITEM', this.resource_class.item)
} catch (e) { } catch (e) {
console.error(e) console.error(e)
if ( e.response && e.response.data && e.response.data.message ) if ( e.response && e.response.data && e.response.data.message )
this.error_message = e.response.data.message this.error_message = e.response.data.message
else this.error_message = 'An unknown error occurred while saving the form.' else this.error_message = this.t['common.unknown_error']
} }
} }
@ -305,13 +318,13 @@ export default class FormComponent extends Component {
let valid = true let valid = true
for ( const field of this.definition.fields ) { for ( const field of this.definition.fields ) {
if ( (Array.isArray(field.required) ? field.required.includes(this.mode) : field.required) && (!(field.field in this.data) || !this.data[field.field]) ) { if ( (Array.isArray(field.required) ? field.required.includes(this.mode) : field.required) && (!(field.field in this.data) || !this.data[field.field]) ) {
field.error = 'This field is required.' field.error = this.t['common.field_required']
valid = false valid = false
} else if ( field.type === 'password' && this.data[field.field] !== this.data[field.field + '-confirm'] ) { } else if ( field.type === 'password' && this.data[field.field] !== this.data[field.field + '-confirm'] ) {
field.error = field.name + ' confirmation does not match.' field.error = field.name + ' ' + this.t['common.confirmation_not_match']
valid = false valid = false
} else if ( field.type === 'json' && !this.is_json(this.data[field.field]) ) { } else if ( field.type === 'json' && !this.is_json(this.data[field.field]) ) {
field.error = field.name + ' must be valid JSON.' field.error = field.name + ' ' + this.t['common.invalid_json']
valid = false valid = false
} else { } else {
field.error = '' field.error = ''

View File

@ -9,6 +9,8 @@ import AppSetupComponent from './dash/AppSetup.component.js'
import ListingComponent from './cobalt/Listing.component.js' import ListingComponent from './cobalt/Listing.component.js'
import FormComponent from './cobalt/Form.component.js' import FormComponent from './cobalt/Form.component.js'
import { T } from './service/Translate.service.js'
const dash_components = { const dash_components = {
SideBarComponent, SideBarComponent,
NavBarComponent, NavBarComponent,

View File

@ -18,4 +18,12 @@ module.exports = exports = {
unknown_error: 'An unknown error has occurred, and we are unable to continue at this time.', unknown_error: 'An unknown error has occurred, and we are unable to continue at this time.',
invalid_resolver: 'Invalid locale resolver.', invalid_resolver: 'Invalid locale resolver.',
loading: 'Loading',
confirm: 'Confirm',
save: 'Save',
field_required: 'This field is required.',
confirmation_not_match: 'confirmation does not match.',
invalid_json: 'must be valid JSON.',
not_permission: 'Sorry, you do not have permission to ACTION this resource.',
item_saved: 'The ITEM was saved.',
} }

View File

@ -20,4 +20,24 @@ module.exports = exports = {
normal_code: 'Have a normal MFA code?', normal_code: 'Have a normal MFA code?',
recover_success: 'Success! There are only NUM_CODES recovery codes remaining. Let\'s get you on your way...', recover_success: 'Success! There are only NUM_CODES recovery codes remaining. Let\'s get you on your way...',
setup_prompt: `
We're going to walk you through setting up multi-factor authentication for your account.
<br><br>
Once this is completed, you will need to provide your second factor of authentication whenever you sign in with your APP_NAME account.
<br><br>
You'll need some kind of MFA token generator such as Google Authenticator.
`,
setup_qr_prompt: `
Scan the QR code below with your authenticator app to add your APP_NAME account.
<br><br>
Once you've done this, we'll ask for one of the generated codes to verify that MFA is working correctly.
`,
secret: 'Secret:',
setup_success: `
Now, enter the code displayed in your authenticator app. APP_NAME will verify that the code is
correct. Then, you can enable MFA for your account.
`,
enable_mfa: 'Enable MFA',
setup_code_success: 'Success! That code matched what APP_NAME was expecting. You can now enable multi-factor authentication for your account.',
mfa_enabled: 'MFA has been enabled for your account! For security purposes, you will be asked to sign in again.',
} }

View File

@ -0,0 +1,11 @@
module.exports = exports = {
reset_prompt: 'We\'re going to walk you through resetting your APP_NAME password.',
reset_invalidates: 'Note that this process will invalidate any existing app passwords you have created.',
enter_new_pw: 'Please enter a new password for your account:',
calc_time: 'This password would take CALC_TIME to crack.',
confirm: 'Confirm the password:',
new_password: 'New Password',
confirm_password: 'Confirm the Password',
change: 'Change Password',
reset_success: 'Your password was reset. For security reasons, you will be asked to sign-in again.',
}