Removes old awkward JS translations endpoint.
New system still a little akward in code but not now in process.
Also extracted out page editors into their own files.
Closes #1258
return view('common.home', $commonData);
}
- /**
- * Get a js representation of the current translations
- * @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
- * @throws \Exception
- */
- public function getTranslations()
- {
- $locale = app()->getLocale();
- $cacheKey = 'GLOBAL_TRANSLATIONS_' . $locale;
-
- if (cache()->has($cacheKey) && config('app.env') !== 'development') {
- $resp = cache($cacheKey);
- } else {
- $translations = [
- // Get only translations which might be used in JS
- 'common' => trans('common'),
- 'components' => trans('components'),
- 'entities' => trans('entities'),
- 'errors' => trans('errors')
- ];
- $resp = 'window.translations = ' . json_encode($translations);
- cache()->put($cacheKey, $resp, 120);
- }
-
- return response($resp, 200, [
- 'Content-Type' => 'application/javascript'
- ]);
- }
-
/**
* Get custom head HTML, Used in ajax calls to show in editor.
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
return "<?php echo icon($expression); ?>";
});
+ Blade::directive('exposeTranslations', function($expression) {
+ return "<?php \$__env->startPush('translations'); ?>" .
+ "<?php foreach({$expression} as \$key): ?>" .
+ '<meta name="translation" key="<?php echo e($key); ?>" value="<?php echo e(trans($key)); ?>">' . "\n" .
+ "<?php endforeach; ?>" .
+ '<?php $__env->stopPush(); ?>';
+ });
+
// Allow longer string lengths after upgrade to utf8mb4
Schema::defaultStringLength(191);
// Translation setup
// Creates a global function with name 'trans' to be used in the same way as Laravel's translation system
import Translations from "./services/translations"
-const translator = new Translations(window.translations);
+const translator = new Translations();
window.trans = translator.get.bind(translator);
window.trans_choice = translator.getPlural.bind(translator);
* @param translations
*/
constructor(translations) {
- this.store = translations;
+ this.store = new Map();
+ this.parseTranslations();
+ }
+
+ /**
+ * Parse translations out of the page and place into the store.
+ */
+ parseTranslations() {
+ const translationMetaTags = document.querySelectorAll('meta[name="translation"]');
+ for (let tag of translationMetaTags) {
+ const key = tag.getAttribute('key');
+ const value = tag.getAttribute('value');
+ this.store.set(key, value);
+ }
}
/**
* @returns {*}
*/
get(key, replacements) {
- let text = this.getTransText(key);
+ const text = this.getTransText(key);
return this.performReplacements(text, replacements);
}
* @returns {*}
*/
getPlural(key, count, replacements) {
- let text = this.getTransText(key);
- let splitText = text.split('|');
+ const text = this.getTransText(key);
+ const splitText = text.split('|');
+ const exactCountRegex = /^{([0-9]+)}/;
+ const rangeRegex = /^\[([0-9]+),([0-9*]+)]/;
let result = null;
- let exactCountRegex = /^{([0-9]+)}/;
- let rangeRegex = /^\[([0-9]+),([0-9*]+)]/;
- for (let i = 0, len = splitText.length; i < len; i++) {
- let t = splitText[i];
+ for (const i = 0, len = splitText.length; i < len; i++) {
+ const t = splitText[i];
// Parse exact matches
- let exactMatches = t.match(exactCountRegex);
+ const exactMatches = t.match(exactCountRegex);
if (exactMatches !== null && Number(exactMatches[1]) === count) {
result = t.replace(exactCountRegex, '').trim();
break;
}
// Parse range matches
- let rangeMatches = t.match(rangeRegex);
+ const rangeMatches = t.match(rangeRegex);
if (rangeMatches !== null) {
- let rangeStart = Number(rangeMatches[1]);
+ const rangeStart = Number(rangeMatches[1]);
if (rangeStart <= count && (rangeMatches[2] === '*' || Number(rangeMatches[2]) >= count)) {
result = t.replace(rangeRegex, '').trim();
break;
* @returns {String|Object}
*/
getTransText(key) {
- let splitKey = key.split('.');
- let value = splitKey.reduce((a, b) => {
- return a !== undefined ? a[b] : a;
- }, this.store);
+ const value = this.store.get(key);
if (value === undefined) {
- console.log(`Translation with key "${key}" does not exist`);
- value = key;
+ console.warn(`Translation with key "${key}" does not exist`);
}
return value;
*/
performReplacements(string, replacements) {
if (!replacements) return string;
- let replaceMatches = string.match(/:([\S]+)/g);
+ const replaceMatches = string.match(/:([\S]+)/g);
if (replaceMatches === null) return string;
replaceMatches.forEach(match => {
- let key = match.substring(1);
+ const key = match.substring(1);
if (typeof replacements[key] === 'undefined') return;
string = string.replace(match, replacements[key]);
});
<link rel="stylesheet" href="{{ versioned_asset('dist/styles.css') }}">
<link rel="stylesheet" media="print" href="{{ versioned_asset('dist/print-styles.css') }}">
- <!-- Scripts -->
- <script src="{{ baseUrl('/translations') }}"></script>
-
@yield('head')
+
+ <!-- Custom Styles & Head Content -->
@include('partials.custom-styles')
@include('partials.custom-head')
@stack('head')
+
+ <!-- Translations for JS -->
+ @stack('translations')
+
</head>
<body class="@yield('body-class')">
<div page-comments page-id="{{ $page->id }}" class="comments-list">
+
+ @exposeTranslations([
+ 'entities.comment_updated_success',
+ 'entities.comment_deleted_success',
+ 'entities.comment_created_success',
+ 'entities.comment_count',
+ ])
+
<div comment-count-bar class="grid half left-focus v-center no-row-gap">
<h5 comments-title>{{ trans_choice('entities.comment_count', count($page->comments), ['count' => count($page->comments)]) }}</h5>
@if (count($page->comments) === 0)
<div id="image-manager" image-type="{{ $imageType }}" uploaded-to="{{ $uploaded_to ?? 0 }}">
+
+ @exposeTranslations([
+ 'components.image_delete_success',
+ 'components.image_upload_success',
+ 'errors.server_upload_limit',
+ 'components.image_upload_remove',
+ 'components.file_upload_timeout',
+ ])
+
<div overlay v-cloak @click="hide">
<div class="popup-body" @click.stop="">
<div class="flex-fill flex">
<form action="{{ $page->getUrl() }}" autocomplete="off" data-page-id="{{ $page->id }}" method="POST" class="flex flex-fill">
+ {{ csrf_field() }}
+
@if(!isset($isDraft))
<input type="hidden" name="_method" value="PUT">
@endif
@if(userCan('attachment-create-all'))
<div toolbox-tab-content="files" id="attachment-manager" page-id="{{ $page->id ?? 0 }}">
+
+ @exposeTranslations([
+ 'entities.attachments_file_uploaded',
+ 'entities.attachments_file_updated',
+ 'entities.attachments_link_attached',
+ 'entities.attachments_updated_success',
+ 'errors.server_upload_limit',
+ 'components.image_upload_remove',
+ 'components.file_upload_timeout',
+ ])
+
<h4>{{ trans('entities.attachments') }}</h4>
<div class="px-l files">
-
<div class="page-editor flex-fill flex" id="page-editor"
drafts-enabled="{{ $draftsEnabled ? 'true' : 'false' }}"
drawio-enabled="{{ config('services.drawio') ? 'true' : 'false' }}"
page-new-draft="{{ $model->draft ?? 0 }}"
page-update-draft="{{ $model->isDraft ?? 0 }}">
- {{ csrf_field() }}
+ @exposeTranslations([
+ 'entities.pages_editing_draft',
+ 'entities.pages_editing_page',
+ 'errors.page_draft_autosave_fail',
+ 'entities.pages_editing_page',
+ 'entities.pages_draft_discarded',
+ 'entities.pages_edit_set_changelog',
+ ])
{{--Header Bar--}}
<div class="primary-background-light toolbar page-edit-toolbar">
{{--WYSIWYG Editor--}}
@if(setting('app-editor') === 'wysiwyg')
- <div wysiwyg-editor class="flex-fill flex">
- <textarea id="html-editor" name="html" rows="5" v-pre
- @if($errors->has('html')) class="text-neg" @endif>@if(isset($model) || old('html')){{htmlspecialchars( old('html') ? old('html') : $model->html)}}@endif</textarea>
- </div>
-
- @if($errors->has('html'))
- <div class="text-neg text-small">{{ $errors->first('html') }}</div>
- @endif
+ @include('pages.wysiwyg-editor', ['model' => $model])
@endif
{{--Markdown Editor--}}
@if(setting('app-editor') === 'markdown')
- <div v-pre id="markdown-editor" markdown-editor class="flex-fill flex code-fill">
-
- <div class="markdown-editor-wrap active">
- <div class="editor-toolbar">
- <span class="float left editor-toolbar-label">{{ trans('entities.pages_md_editor') }}</span>
- <div class="float right buttons">
- @if(config('services.drawio'))
- <button class="text-button" type="button" data-action="insertDrawing">@icon('drawing'){{ trans('entities.pages_md_insert_drawing') }}</button>
- | 
- @endif
- <button class="text-button" type="button" data-action="insertImage">@icon('image'){{ trans('entities.pages_md_insert_image') }}</button>
- |
- <button class="text-button" type="button" data-action="insertLink">@icon('link'){{ trans('entities.pages_md_insert_link') }}</button>
- </div>
- </div>
-
- <div markdown-input class="flex flex-fill">
- <textarea id="markdown-editor-input" name="markdown" rows="5"
- @if($errors->has('markdown')) class="text-neg" @endif>@if(isset($model) || old('markdown')){{htmlspecialchars( old('markdown') ? old('markdown') : ($model->markdown === '' ? $model->html : $model->markdown))}}@endif</textarea>
- </div>
-
- </div>
-
- <div class="markdown-editor-wrap">
- <div class="editor-toolbar">
- <div class="editor-toolbar-label">{{ trans('entities.pages_md_preview') }}</div>
- </div>
- <div class="markdown-display page-content">
- </div>
- </div>
- <input type="hidden" name="html"/>
-
- </div>
-
-
-
- @if($errors->has('markdown'))
- <div class="text-neg text-small">{{ $errors->first('markdown') }}</div>
- @endif
+ @include('pages.markdown-editor', ['model' => $model])
@endif
</div>
--- /dev/null
+<div v-pre id="markdown-editor" markdown-editor class="flex-fill flex code-fill">
+ @exposeTranslations([
+ 'errors.image_upload_error',
+ ])
+
+ <div class="markdown-editor-wrap active">
+ <div class="editor-toolbar">
+ <span class="float left editor-toolbar-label">{{ trans('entities.pages_md_editor') }}</span>
+ <div class="float right buttons">
+ @if(config('services.drawio'))
+ <button class="text-button" type="button" data-action="insertDrawing">@icon('drawing'){{ trans('entities.pages_md_insert_drawing') }}</button>
+ | 
+ @endif
+ <button class="text-button" type="button" data-action="insertImage">@icon('image'){{ trans('entities.pages_md_insert_image') }}</button>
+ |
+ <button class="text-button" type="button" data-action="insertLink">@icon('link'){{ trans('entities.pages_md_insert_link') }}</button>
+ </div>
+ </div>
+
+ <div markdown-input class="flex flex-fill">
+ <textarea id="markdown-editor-input" name="markdown" rows="5"
+ @if($errors->has('markdown')) class="text-neg" @endif>@if(isset($model) || old('markdown')){{htmlspecialchars( old('markdown') ? old('markdown') : ($model->markdown === '' ? $model->html : $model->markdown))}}@endif</textarea>
+ </div>
+
+ </div>
+
+ <div class="markdown-editor-wrap">
+ <div class="editor-toolbar">
+ <div class="editor-toolbar-label">{{ trans('entities.pages_md_preview') }}</div>
+ </div>
+ <div class="markdown-display page-content">
+ </div>
+ </div>
+ <input type="hidden" name="html"/>
+
+</div>
+
+
+
+@if($errors->has('markdown'))
+ <div class="text-neg text-small">{{ $errors->first('markdown') }}</div>
+@endif
\ No newline at end of file
--- /dev/null
+<div wysiwyg-editor class="flex-fill flex">
+
+ @exposeTranslations([
+ 'errors.image_upload_error',
+ ])
+
+ <textarea id="html-editor" name="html" rows="5" v-pre
+ @if($errors->has('html')) class="text-neg" @endif>@if(isset($model) || old('html')){{htmlspecialchars( old('html') ? old('html') : $model->html)}}@endif</textarea>
+</div>
+
+@if($errors->has('html'))
+ <div class="text-neg text-small">{{ $errors->first('html') }}</div>
+@endif
\ No newline at end of file
<?php
-Route::get('/translations', 'HomeController@getTranslations');
Route::get('/robots.txt', 'HomeController@getRobots');
// Authenticated routes...