~tijlvdb/coral

8e02a385e7282c540b41f37c567bb747ff0ed2b6 — Tijl Van den Brugghen 8 months ago 1e6086f master
Draft (but working) implementation of a multi-language setup
3 files changed, 112 insertions(+), 6 deletions(-)

M app/Helpers/Wiki.php
M theme/navbar.html
M theme/static/main.css
M app/Helpers/Wiki.php => app/Helpers/Wiki.php +61 -0
@@ 41,9 41,18 @@ class Wiki extends \Prefab
			'file_path' => $local_path,
			'markdown' => $markdown,
			'html' => $this->renderPage($markdown),
			'languages' => $this->getPageLanguages($full_path),
			'cached' => false
		]);
		
		// Detect the current language
		foreach ($result['languages'] as $lang) {
			if ($lang['active']) {
				$result['language'] = $lang;
				break;
			}
		}
		
		// Cache for a day
		$f3->set($cache_key, [
			'mtime' => filemtime($full_path),


@@ 70,6 79,13 @@ class Wiki extends \Prefab
		$path = str_replace('//', '/', $path);
		$data_dir = \Base::instance()->get('config.data_dir');
		$test_paths = [$path . '.md', $path . '/index.md'];
		$languages = \Base::instance()->get('config.list_languages');
		
		if (!empty($languages)) {
			foreach ($languages as $lang_code => $lang) {
				array_push($test_paths, $path . '/index.' . $lang_code . '.md');
			}
		}
		
		foreach ($test_paths as $p) {
			if (file_exists($data_dir . $p)) {


@@ 92,6 108,51 @@ class Wiki extends \Prefab
		return 'No title';
	}
	
	/**
	 * Returns a list of objects containing a language code and a path to the file, relative to the data directory.
	 * Returns an empty array if the language list is disabled.
	 *
	 * @param string $path Full path to the page or relative to the data directory.
	 */
	public function getPageLanguages(string $path)
	{
		$f3 = \Base::instance();
		$data_dir = $f3->get('config.data_dir');
		$languages = $f3->get('config.list_languages');
		
		if (empty($languages)) return [];
		
		$path = str_replace($data_dir, '', $path);
		
		if (substr($path, -3) === '.md') {
			$path = substr($path, 0, -3);
		}
		
		$dot_pos = strrpos($path, '.');
		if ($dot_pos !== false && in_array(($current_lang_code = substr($path, $dot_pos + 1)), array_keys($languages))) {
			$supported_languages = [];
			$raw_filename = substr($path, 0, $dot_pos);
			
			foreach ($languages as $lang_code => $lang) {
				$filename = $raw_filename . '.' . $lang_code . '.md';
				$full_path = $data_dir . $filename;
				
				if (is_file($full_path)) {
					array_push($supported_languages, [
						'code' => $lang_code,
						'language' => $lang,
						'filename' => trim($filename, '/'),
						'active' => $lang_code === $current_lang_code
					]);
				}
			}
			
			return $supported_languages;
		} else {
			return [];
		}
	}
	
	protected function renderPage(string $markdown)
	{
		$parsedown = new ParsedownCheckbox();

M theme/navbar.html => theme/navbar.html +31 -4
@@ 2,8 2,35 @@
    <div class="container">
        <a href="/" class="navbar-title">{{ @config.site_name }}</a>

        <a href="/_/sitemap" class="btn btn-secondary sitemap-link ml-auto">
            <include href="static/sitemap.svg"></include>
        </a>
        <div class="ml-auto flex-row">
            <check if="{{ !empty(@page) && !empty(@page.languages) }}">
                <select id="language-selector">
                    <repeat group="{{ @page.languages }}" value="{{ @lang }}">
                        <option value="{{ @lang.code }}" data-filename="{{ @lang.filename }}"{{ @lang.active ? ' selected' : '' }}>{{ @lang.language }} ({{
                            @lang.code }})
                        </option>
                    </repeat>
                </select>
            </check>

            <a href="/_/sitemap" class="btn btn-secondary sitemap-link">
                <include href="static/sitemap.svg"></include>
            </a>
        </div>
    </div>
</div>
\ No newline at end of file
</div>

<script>
    var languageSelector = document.getElementById('language-selector');

    if (languageSelector) {
        languageSelector.addEventListener('change',
            function () {
                var option = languageSelector[languageSelector.selectedIndex];
                var filename = option.getAttribute('data-filename');

                window.location = '/' + filename.substring(0, filename.length - 3);
            }
        )
    }
</script>
\ No newline at end of file

M theme/static/main.css => theme/static/main.css +20 -2
@@ 214,7 214,7 @@ table th:last-child {
    align-items: center;
    background-color: rgba(255, 255, 255, 0.2);
    padding: 8px 9px;
    margin: -8px 0 -8px -9px;
    margin-left: 9px;
    border-radius: 3px;
}



@@ 260,4 260,22 @@ footer {
/*    opacity: 0.3;*/
/*    font-weight: bold;*/
/*    font-size: 1em;*/
/*}*/
\ No newline at end of file
/*}*/

/*
 * FLEX UTILITIES
 */

.d-flex {
    display: flex;
}

.flex-row {
    display: flex;
    flex-direction: row;
}

.flex-column {
    display: flex;
    flex-direction: column;
}
\ No newline at end of file