mirror of
https://github.com/Bubka/2FAuth.git
synced 2024-11-22 16:23:18 +01:00
Add support of the Accept_language header for UI localization
This commit is contained in:
parent
fbe91cc90e
commit
9f574feada
@ -3,6 +3,7 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Services\SettingService;
|
||||
use Illuminate\Support\Facades\App;
|
||||
|
||||
class SinglePageController extends Controller
|
||||
{
|
||||
@ -31,7 +32,8 @@ public function index()
|
||||
{
|
||||
return view('landing')->with([
|
||||
'appSettings' => $this->settingService->all()->toJson(),
|
||||
'lang' => $this->settingService->get('lang')
|
||||
'lang' => App::currentLocale(),
|
||||
'locales' => collect(config("2fauth.locales"))->toJson(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Facades\App\Services\SettingService;
|
||||
|
||||
class SetLanguage
|
||||
@ -16,7 +17,25 @@ class SetLanguage
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
\App::setLocale(SettingService::get('lang', 'en'));
|
||||
// 3 possible cases here:
|
||||
// - The user has choosen a specific language among those available in the Setting view of 2FAuth
|
||||
// - The client send an accept-language header
|
||||
// - No language is passed from the client
|
||||
//
|
||||
// We prioritize the user defined one, then the request header one, and finally the fallback one.
|
||||
// FI: SettingService::get() always returns a fallback value
|
||||
$lang = SettingService::get('lang');
|
||||
|
||||
if($lang === 'browser') {
|
||||
if ($request->hasHeader("Accept-Language")) {
|
||||
// We only keep the primary language passed via the header.
|
||||
$lang = head(explode(',', $request->header("Accept-Language")));
|
||||
}
|
||||
else $lang = config('app.fallback_locale');
|
||||
}
|
||||
|
||||
// If the language is not available (or partial), strings will be translated using the fallback language.
|
||||
App::setLocale($lang);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
@ -5,14 +5,29 @@
|
||||
use Throwable;
|
||||
use Exception;
|
||||
use App\Models\Option;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use App\Exceptions\DbEncryptionException;
|
||||
|
||||
class SettingService
|
||||
{
|
||||
|
||||
/**
|
||||
* Determine if the given setting has been customized by the user
|
||||
*
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public function isUserDefined($key) : bool
|
||||
{
|
||||
return DB::table('options')->where('key', $key)->exists();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a setting
|
||||
*
|
||||
@ -40,9 +55,15 @@ public function all() : Collection
|
||||
$userOptions->transform(function ($item, $key) {
|
||||
return $this->restoreType($item);
|
||||
});
|
||||
$userOptions = collect(config('2fauth.options'))->merge($userOptions);
|
||||
|
||||
return $userOptions;
|
||||
// Merge 2fauth/app config values as fallback values
|
||||
$settings = collect(config('2fauth.options'))->merge($userOptions);
|
||||
|
||||
if(!Arr::has($settings, 'lang')) {
|
||||
$settings['lang'] = 'browser';
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
|
||||
|
@ -13,6 +13,19 @@
|
||||
'isDemoApp' => env('IS_DEMO_APP', false),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 2FAuth available translations
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
*/
|
||||
|
||||
'locales' => [
|
||||
'en',
|
||||
'fr',
|
||||
'de'
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application fallback for user options
|
||||
|
@ -8,6 +8,7 @@
|
||||
<h4 class="title is-4 has-text-grey-light">{{ $t('settings.general') }}</h4>
|
||||
<!-- Language -->
|
||||
<form-select v-on:lang="saveSetting('lang', $event)" :options="langs" :form="form" fieldName="lang" :label="$t('settings.forms.language.label')" :help="$t('settings.forms.language.help')" />
|
||||
<div class="field help">{{ $t('settings.forms.some_translation_are_missing') }}<a class="ml-2" href="https://crowdin.com/project/2fauth">{{ $t('settings.forms.help_translate_2fauth') }}</a></div>
|
||||
<!-- display mode -->
|
||||
<form-toggle v-on:displayMode="saveSetting('displayMode', $event)" :choices="layouts" :form="form" fieldName="displayMode" :label="$t('settings.forms.display_mode.label')" :help="$t('settings.forms.display_mode.help')" />
|
||||
<!-- show icon -->
|
||||
@ -74,7 +75,7 @@
|
||||
data(){
|
||||
return {
|
||||
form: new Form({
|
||||
lang: '',
|
||||
lang: 'browser',
|
||||
showOtpAsDot: null,
|
||||
closeOtpOnCopy: null,
|
||||
useBasicQrcodeReader: null,
|
||||
@ -87,11 +88,6 @@
|
||||
defaultCaptureMode: '',
|
||||
rememberActiveGroup: true,
|
||||
}),
|
||||
langs: [
|
||||
{ text: this.$t('languages.en'), value: 'en' },
|
||||
{ text: this.$t('languages.fr'), value: 'fr' },
|
||||
{ text: this.$t('languages.de'), value: 'de' },
|
||||
],
|
||||
layouts: [
|
||||
{ text: this.$t('settings.forms.grid'), value: 'grid', icon: 'th' },
|
||||
{ text: this.$t('settings.forms.list'), value: 'list', icon: 'list' },
|
||||
@ -119,11 +115,36 @@
|
||||
}
|
||||
},
|
||||
|
||||
computed : {
|
||||
langs: function() {
|
||||
let locales = [{
|
||||
text: this.$t('languages.browser_preference') + ' (' + this.$root.$i18n.locale + ')',
|
||||
value: 'browser'
|
||||
}];
|
||||
|
||||
for (const locale of window.appLocales) {
|
||||
locales.push({
|
||||
text: this.$t('languages.' + locale),
|
||||
value: locale
|
||||
})
|
||||
}
|
||||
return locales
|
||||
}
|
||||
},
|
||||
|
||||
async mounted() {
|
||||
const { data } = await this.form.get('/api/v1/settings')
|
||||
|
||||
this.form.fillWithKeyValueObject(data)
|
||||
this.form.lang = this.$root.$i18n.locale
|
||||
let lang = data.filter(x => x.key === 'lang')
|
||||
|
||||
if (lang.value == 'browser') {
|
||||
if(window.appLocales.includes(lang.value)) {
|
||||
this.form.lang = lang
|
||||
}
|
||||
}
|
||||
// this.$root.$i18n.locale
|
||||
|
||||
this.form.setOriginal()
|
||||
this.fetchGroups()
|
||||
},
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
|
||||
*/
|
||||
|
||||
'browser_preference' => 'Browser preference',
|
||||
'en' => 'English',
|
||||
'fr' => 'French',
|
||||
'de' => 'German',
|
||||
|
@ -39,9 +39,11 @@
|
||||
'edit_settings' => 'Edit settings',
|
||||
'setting_saved' => 'Settings saved',
|
||||
'new_token' => 'New token',
|
||||
'some_translation_are_missing' => 'Some translations are missing using the browser preferred language?',
|
||||
'help_translate_2fauth' => 'Help translate 2FAuth',
|
||||
'language' => [
|
||||
'label' => 'Language',
|
||||
'help' => 'Change the language used to translate the app interface.'
|
||||
'help' => 'Language used to translate the 2FAuth user interface. Named languages are complete, set the one of your choice to override your browser preference.'
|
||||
],
|
||||
'show_otp_as_dot' => [
|
||||
'label' => 'Show generated one-time passwords as dot',
|
||||
|
@ -25,6 +25,7 @@
|
||||
<script type="text/javascript">
|
||||
var appSettings = {!! $appSettings !!};
|
||||
var appVersion = '{{ config("app.version") }}';
|
||||
var appLocales = {!! $locales !!};
|
||||
</script>
|
||||
<script src="{{ mix('js/manifest.js') }}"></script>
|
||||
<script src="{{ mix('js/vendor.js') }}"></script>
|
||||
|
Loading…
Reference in New Issue
Block a user