diff --git a/src/.env.example b/src/.env.example --- a/src/.env.example +++ b/src/.env.example @@ -6,6 +6,8 @@ APP_PUBLIC_URL= APP_DOMAIN=kolabnow.com APP_THEME=default +APP_LOCALE=en +APP_LOCALES=en,de ASSET_URL=http://127.0.0.1:8000 diff --git a/src/app/Http/Controllers/ContentController.php b/src/app/Http/Controllers/ContentController.php --- a/src/app/Http/Controllers/ContentController.php +++ b/src/app/Http/Controllers/ContentController.php @@ -17,14 +17,17 @@ abort(404); } + $theme = \config('app.theme'); $page = str_replace('/', '.', $page); - $file = sprintf('themes/%s/pages/%s.blade.php', \config('app.theme'), $page); - $view = sprintf('%s.pages.%s', \config('app.theme'), $page); + $file = sprintf('themes/%s/pages/%s.blade.php', $theme, $page); + $view = sprintf('%s.pages.%s', $theme, $page); if (!file_exists(resource_path($file))) { abort(404); } + self::loadLocale($theme); + return view($view)->with('env', \App\Utils::uiEnv()); } @@ -59,4 +62,16 @@ return response()->json(['status' => 'success', 'faq' => $faq]); } + + /** + * Register localization files from the theme. + * + * @param string $theme Theme name + */ + protected static function loadLocale(string $theme): void + { + $path = resource_path(sprintf('themes/%s/lang', $theme)); + + \app('translator')->addNamespace('theme', $path); + } } diff --git a/src/app/Http/Kernel.php b/src/app/Http/Kernel.php --- a/src/app/Http/Kernel.php +++ b/src/app/Http/Kernel.php @@ -21,6 +21,7 @@ \App\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, \App\Http\Middleware\DevelConfig::class, + \App\Http\Middleware\Locale::class, // FIXME: CORS handling added here, I didn't find a nice way // to add this only to the API routes // \App\Http\Middleware\Cors::class, diff --git a/src/app/Http/Middleware/Locale.php b/src/app/Http/Middleware/Locale.php new file mode 100644 --- /dev/null +++ b/src/app/Http/Middleware/Locale.php @@ -0,0 +1,43 @@ +getLanguages() + ); + + $default = config('app.locale'); + $lang = null; + + foreach ($preferences as $pref) { + if (!empty($pref) && ($pref == $default || file_exists("$langDir/$pref"))) { + $lang = $pref; + break; + } + } + + if ($lang != $default) { + app()->setLocale($lang); + } + + return $next($request); + } +} diff --git a/src/app/Utils.php b/src/app/Utils.php --- a/src/app/Utils.php +++ b/src/app/Utils.php @@ -402,6 +402,12 @@ $env['menu'] = $menu; + if (!empty(\env('APP_LOCALES'))) { + $env['languages'] = preg_split('/\s*,\s*/', strtolower(trim(\env('APP_LOCALES')))); + } else { + $env['languages'] = ['en', 'de']; + } + return $env; } } diff --git a/src/config/app.php b/src/config/app.php --- a/src/config/app.php +++ b/src/config/app.php @@ -98,7 +98,7 @@ | */ - 'locale' => 'en', + 'locale' => env('APP_LOCALE', 'en'), /* |-------------------------------------------------------------------------- diff --git a/src/package-lock.json b/src/package-lock.json --- a/src/package-lock.json +++ b/src/package-lock.json @@ -1519,7 +1519,11 @@ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "dev": true, - "optional": true + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } }, "glob-parent": { "version": "3.1.0", @@ -2746,6 +2750,16 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -5512,6 +5526,13 @@ "integrity": "sha512-UssQP5ZgIOKelfsaB5CuGAL+Y+q7EmONuiwF3N5HAH0t27rvrttgi6Ra9k/+DVaY9UF6+ybxu5pOXLUdA8N7Vg==", "dev": true }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -7864,6 +7885,13 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "nan": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "dev": true, + "optional": true + }, "nanoid": { "version": "3.1.22", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.22.tgz", @@ -13758,6 +13786,12 @@ "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==", "dev": true }, + "vue-i18n": { + "version": "8.24.2", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.24.2.tgz", + "integrity": "sha512-+TkAPBQw4Cp2bQrSPtPNkhET7XcWYjjDt1UjWYQs+xbT41q5OAl1I3IZyhg0drjn1nlC1K0f8sLVB/nshUcF1Q==", + "dev": true + }, "vue-loader": { "version": "15.9.6", "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.9.6.tgz", diff --git a/src/package.json b/src/package.json --- a/src/package.json +++ b/src/package.json @@ -34,6 +34,7 @@ "stylelint": "^13.12.0", "stylelint-config-standard": "^20.0.0", "vue": "^2.6.12", + "vue-i18n": "^8.24.1", "vue-loader": "^15.9.6", "vue-router": "^3.5.1", "vue-template-compiler": "^2.6.12", diff --git a/src/resources/js/app.js b/src/resources/js/app.js --- a/src/resources/js/app.js +++ b/src/resources/js/app.js @@ -10,6 +10,7 @@ import MenuComponent from '../vue/Widgets/Menu' import SupportForm from '../vue/Widgets/SupportForm' import store from './store' +import { loadLangAsync, i18n } from './locale' const loader = '