diff --git a/HOWTO.md b/HOWTO.md deleted file mode 100644 index 99b18ff..0000000 --- a/HOWTO.md +++ /dev/null @@ -1,220 +0,0 @@ -# Quick Site Generator 2 (qsgen2) - User Guide - -## Table of Contents -1. [Introduction](#introduction) -2. [Installation](#installation) -3. [Quick Start](#quick-start) -4. [Project Structure](#project-structure) -5. [Content Creation](#content-creation) - - [Pages](#pages) - - [Blog Posts](#blog-posts) -6. [Markup Languages](#markup-languages) - - [QSTags](#qstags) - - [Markdown](#markdown) - - [Conversion Between Formats](#conversion-between-formats) -7. [Themes and Templates](#themes-and-templates) -8. [Configuration](#configuration) -9. [Command Reference](#command-reference) -10. [Advanced Usage](#advanced-usage) -11. [Troubleshooting](#troubleshooting) -12. [Contributing](#contributing) - -## Introduction - -Quick Site Generator 2 (qsgen2) is a powerful static site generator written in Zsh. It's designed to be fast, flexible, and easy to use, with support for both custom QSTags and standard Markdown syntax. - -## Installation - -1. Clone the repository: - ```bash - git clone https://github.com/kekePower/qsgen2.git - cd qsgen2 - ``` - -2. Make the script executable: - ```bash - chmod +x qsgen2 - ``` - -3. Add to your PATH (optional): - ```bash - echo 'export PATH="$PATH:'$(pwd)'"' >> ~/.zshrc - source ~/.zshrc - ``` - -## Quick Start - -1. Create a new site: - ```bash - ./qsgen2 new my-site - cd my-site - ``` - -2. Build the site: - ```bash - ./qsgen2 build - ``` - -3. Preview the site: - ```bash - ./qsgen2 serve - ``` - -## Project Structure - -``` -my-site/ -├── config # Site configuration -├── content/ # Source content -│ ├── pages/ # Static pages -│ └── blog/ # Blog posts -├── themes/ # Site themes -├── static/ # Static files (images, CSS, JS) -└── output/ # Generated site (created on build) -``` - -## Content Creation - -### Pages - -Create a new page: -```bash -./qsgen2 new page about -``` - -Pages use the `.qst` extension and can include QSTags or Markdown. - -### Blog Posts - -Create a new blog post: -```bash -./qsgen2 new post my-first-post -``` - -Blog posts use the `.blog` extension and support the same markup as pages. - -## Markup Languages - -### QSTags - -QSTags is a simple markup language used by qsgen2. Example: - -``` -#H1 Welcome to My Site#EH1 -#P This is a paragraph with #BDbold#EBD and #Iitalic#EI text.#EP -``` - -### Markdown - -Markdown is also supported: - -```markdown -# Welcome to My Site - -This is a paragraph with **bold** and *italic* text. -``` - -### Conversion Between Formats - -Convert a single file to Markdown: -```bash -./qsgen2 convert --to-markdown content/pages/about.qst content/pages/about.md -``` - -Convert all files to Markdown: -```bash -./qsgen2 convert --to-markdown --all -``` - -Convert back to QSTags: -```bash -./qsgen2 convert --to-qstags --all -``` - -## Themes and Templates - -Themes are stored in the `themes` directory. Each theme can include: -- Page templates -- Blog post templates -- CSS/JavaScript -- Assets - -## Configuration - -Edit `config/site.conf` to customize your site: - -```ini -site_name = "My Awesome Site" -site_url = "https://example.com" -site_author = "Your Name" -theme = "default" -``` - -## Command Reference - -### Build Commands -- `build`: Build the site -- `clean`: Remove generated files -- `serve`: Start a local server - -### Content Management -- `new page `: Create a new page -- `new post `: Create a new blog post -- `convert`: Convert between markup formats - -### Utility Commands -- `version`: Show version information -- `help`: Show help message - -## Advanced Usage - -### Custom Build Scripts -Create a `build.zsh` file in your project root: - -```bash -#!/usr/bin/env zsh -# Custom build script - -# Clean previous build -./qsgen2 clean - -# Convert all content to Markdown for editing -./qsgen2 convert --to-markdown --all - -# Build the site -./qsgen2 build - -# Optimize images -find output -name "*.jpg" -exec jpegoptim --strip-all {} \; -``` - -## Troubleshooting - -### Common Issues - -1. **Permission Denied** - ```bash - chmod +x qsgen2 - ``` - -2. **Command Not Found** - Add qsgen2 to your PATH or use `./qsgen2` - -3. **Build Errors** - Check for syntax errors in your content files - -## Contributing - -1. Fork the repository -2. Create a feature branch -3. Commit your changes -4. Push to the branch -5. Create a Pull Request - -## License - -MIT License - See LICENSE for details. - ---- - -*Quick Site Generator 2 - A fast, flexible static site generator* diff --git a/THEME-HOWTO.md b/THEME-HOWTO.md deleted file mode 100644 index 02050c0..0000000 --- a/THEME-HOWTO.md +++ /dev/null @@ -1,194 +0,0 @@ -# Creating Themes for Quick Site Generator 2 - -This guide explains how to create and customize themes for Quick Site Generator 2 (qsgen2). The theming system is designed to be simple yet flexible, allowing you to create beautiful, responsive websites with minimal effort. - -## Table of Contents - -1. [Theme Structure](#theme-structure) -2. [Template Files](#template-files) - - [pages.tpl](#pagestpl) - - [blogs.tpl](#blogstpl) - - [blog_index.tpl](#blog_indextpl) - - [blog_list.tpl](#blog_listtpl) -3. [Template Variables](#template-variables) -4. [Creating a New Theme](#creating-a-new-theme) -5. [Best Practices](#best-practices) -6. [Example Theme](#example-theme) - -## Theme Structure - -A qsgen2 theme consists of the following files: - -``` -theme-name/ -├── pages.tpl # Template for regular pages -├── blogs.tpl # Template for blog posts -├── blog_index.tpl # Template for blog index page -├── blog_list.tpl # Template for blog post listings -└── css/ # Stylesheets and assets - ├── style.css # Main stylesheet - └── webfont.js # Web font loader (optional) -``` - -## Template Files - -### pages.tpl - -This template is used for regular static pages. It should include the basic HTML structure, head section, and placeholders for dynamic content. - -Key placeholders: -- `#sitename` - Site name from configuration -- `#pagetitle` - Title of the current page -- `#tagline` - Site tagline from configuration -- `BODY` - Main content area - -### blogs.tpl - -This template is used for individual blog posts. It includes placeholders for blog-specific content. - -Key placeholders: -- `BLOGTITLE` - Title of the blog post -- `CALADAY` - Day of the month (numeric) -- `CALNDAY` - Day of the week (name) -- `CALMONTH` - Month name -- `CALYEAR` - Year -- `INGRESS` - Blog post excerpt/intro -- `BODY` - Main blog post content - -### blog_index.tpl - -This template is used for the blog index/archive page that lists all blog posts. - -Key placeholders: -- `#sitename` - Site name from configuration -- `#tagline` - Site tagline from configuration -- `BODY` - Contains the list of blog posts (generated from blog_list.tpl) - -### blog_list.tpl - -This template defines how individual blog posts are displayed in the blog index. - -Key placeholders: -- `BLOGURL` - URL of the blog post -- `BLOGTITLE` - Title of the blog post -- `INGRESS` - Blog post excerpt/intro -- `BLOGDATE` - Formatted date of the blog post - -## Template Variables - -These variables can be used in any template: - -- `#sitename` - Site name from configuration -- `#tagline` - Site tagline from configuration -- `#pagetitle` - Current page title -- `#siteurl` - Base URL of the site -- `#currentyear` - Current year (for copyright notices) - -## Creating a New Theme - -1. **Create a new directory** in the `themes` folder with your theme name. - -2. **Copy the template files** from the `minimal` theme as a starting point: - ```bash - cp -r themes/minimal/* themes/your-theme-name/ - ``` - -3. **Customize the templates**: - - Edit the HTML structure in the `.tpl` files - - Update the CSS in the `css` directory - - Replace placeholder images with your own - -4. **Test your theme** by setting it in your `site.conf`: - ```ini - theme = "your-theme-name" - ``` - -5. **Build your site** to see the changes: - ```bash - ./qsgen2 build - ``` - -## Best Practices - -1. **Responsive Design** - - Use responsive CSS frameworks or media queries - - Test on different screen sizes - -2. **Performance** - - Minify CSS and JavaScript - - Optimize images - - Use web fonts sparingly - -3. **Accessibility** - - Use semantic HTML5 elements - - Include alt text for images - - Ensure sufficient color contrast - -4. **Browser Compatibility** - - Test in multiple browsers - - Use vendor prefixes for CSS properties - -## Example Theme - -Here's a minimal example of a theme structure: - -``` -my-theme/ -├── pages.tpl -├── blogs.tpl -├── blog_index.tpl -├── blog_list.tpl -└── css/ - └── style.css -``` - -### pages.tpl (example) -```html -<!DOCTYPE html> -<html> -<head> - <meta charset="utf-8"> - <title>#sitename - #pagetitle - - - - -
-

#sitename

-

#tagline

- -
- -
- BODY -
- - - - -``` - -### blog_list.tpl (example) -```html -
-

BLOGTITLE

- -
- INGRESS - Read more → -
-
-``` - -## Conclusion - -Creating themes for qsgen2 is straightforward once you understand the template system. Start with the minimal theme as a base, and customize it to match your design. Remember to test your theme thoroughly and follow web development best practices for the best results. - -For more advanced theming options, refer to the official documentation or check out the source code of existing themes. diff --git a/include/common/colors.inc b/include/common/colors.inc deleted file mode 100755 index 6e571ec..0000000 --- a/include/common/colors.inc +++ /dev/null @@ -1,88 +0,0 @@ -# Here you set the colors you want in the output of view and search -# -# Black 0;30 Dark Gray 1;30 -# Blue 0;34 Light Blue 1;34 -# Green 0;32 Light Green 1;32 -# Cyan 0;36 Light Cyan 1;36 -# Red 0;31 Light Red 1;31 -# Purple 0;35 Light Purple 1;35 -# Brown 0;33 Yellow 1;33 -# Light Gray 0;37 White 1;37 - -BLACK="\033[0;30m" -RED="\033[0;31m" -GREEN="\033[0;32m" -YELLOW="\033[0;33m" -BLUE="\033[0;34m" -MAGENTA="\033[0;35m" -CYAN="\033[0;36m" -WHITE="\033[0;37m" -BOLD_BLACK="\033[1;30m" -BOLD_RED="\033[1;31m" -BOLD_GREEN="\033[1;32m" -BOLD_YELLOW="\033[1;33m" -BOLD_BLUE="\033[1;34m" -BOLD_MAGENTA="\033[1;35m" -BOLD_CYAN="\033[1;36m" -BOLD_WHITE="\033[1;37m" -BLACK_BG="\033[40m" -RED_BG="\033[41m" -GREEN_BG="\033[42m" -YELLOW_BG="\033[43m" -BLUE_BG="\033[44m" -MAGENTA_BG="\033[45m" -CYAN_BG="\033[46m" -WHITE_BG="\033[47m" -END="\033[0m" - -Black="\033[0;30m" -Red="\033[0;31m" -Green="\033[0;32m" -Yellow="\033[0;33m" -Blue="\033[0;34m" -Magenta="\033[0;35m" -Cyan="\033[0;36m" -White="\033[0;37m" -Bold_Black="\033[1;30m" -Bold_Red="\033[1;31m" -Bold_Green="\033[1;32m" -Bold_Yellow="\033[1;33m" -Bold_Blue="\033[1;34m" -Bold_Magenta="\033[1;35m" -Bold_Cyan="\033[1;36m" -Bold_White="\033[1;37m" -Black_bg="\033[40m" -Red_bg="\033[41m" -Green_bg="\033[42m" -Yellow_bg="\033[43m" -Blue_bg="\033[44m" -Magenta_bg="\033[45m" -Cyan_bg="\033[46m" -White_bg="\033[47m" -End="\033[0m" - -black="\033[0;30m" -red="\033[0;31m" -green="\033[0;32m" -yellow="\033[0;33m" -blue="\033[0;34m" -magenta="\033[0;35m" -cyan="\033[0;36m" -white="\033[0;37m" -bold_black="\033[1;30m" -bold_red="\033[1;31m" -bold_green="\033[1;32m" -bold_yellow="\033[1;33m" -bold_blue="\033[1;34m" -bold_magenta="\033[1;35m" -bold_cyan="\033[1;36m" -bold_white="\033[1;37m" -black_bg="\033[40m" -red_bg="\033[41m" -green_bg="\033[42m" -yellow_bg="\033[43m" -blue_bg="\033[44m" -magenta_bg="\033[45m" -cyan_bg="\033[46m" -white_bg="\033[47m" -end="\033[0m" diff --git a/include/common/include b/include/common/include deleted file mode 100644 index aed7a6d..0000000 --- a/include/common/include +++ /dev/null @@ -1,15 +0,0 @@ -function include() { - - # This function is used to include other functions that will normally be in - # ${HOME}/bin/include/ - - # Edit this path to reflect your installation - local inc_file=${HOME}/bin/include/${1}.inc - if [[ ! -f ${inc_file} ]]; then - local inc_opt=$( echo ${1} | cut -d\/ -f2 ) - echo "Supplied option \"${inc_opt}\" is not a valid include." - else - builtin source ${inc_file} ${2} - fi - -} diff --git a/include/common/input_to_array.inc b/include/common/input_to_array.inc deleted file mode 100644 index 7e172be..0000000 --- a/include/common/input_to_array.inc +++ /dev/null @@ -1,11 +0,0 @@ -# Converts a --with=option,option2 into an array -# Usage: InputToArray -# Returns: $InputArray - -function InputToArray () { - - if [[ ${@} =~ "--with" ]]; then - InputArray=( $( echo ${@} | cut -d= -f2 | sed -e 's/\,/\ /g' ) ) - fi - -} diff --git a/include/common/loggy.inc b/include/common/loggy.inc deleted file mode 100644 index dd205a7..0000000 --- a/include/common/loggy.inc +++ /dev/null @@ -1,7 +0,0 @@ -# Function: LOGGER -# Usage: loggy -function loggy () { - - echo "$$ - $(date +%T) - ${KODIVERSION} - ${@}" >> ${LOGGYLOGFILE} - -} diff --git a/include/common/slash_to_array.inc b/include/common/slash_to_array.inc deleted file mode 100644 index 43d0790..0000000 --- a/include/common/slash_to_array.inc +++ /dev/null @@ -1,9 +0,0 @@ -# This function creates an array of a *nix path -# Example: /home/user/bin becomes an array of ( home user bin ) - -function slash_to_array () { - - sta=( $( echo ${1} | sed -e "s/\//\ /g" ) ) - # return ${sta} - -} \ No newline at end of file diff --git a/include/common/zini b/include/common/zini deleted file mode 100644 index 920b661..0000000 --- a/include/common/zini +++ /dev/null @@ -1,39 +0,0 @@ -# zini function to parse INI files and store their content in an associative array -zini() { - local ini_path="$1" - typeset -gA config - - # Check if the file exists - if [[ ! -f "$ini_path" ]]; then - echo "Configuration file not found: $ini_path" - return 1 - fi - - local current_section="" - local line key value composite_key - - # Read the INI file line by line - while IFS= read -r line || [[ -n $line ]]; do - line=$(echo $line | xargs) # Trim whitespace - - # Skip empty lines and comments - [[ -z "$line" || "$line" == \;* ]] && continue - - # Detect section headers - if [[ "$line" == \[*\]* ]]; then - current_section="${line:1:-1}" - else - # Parse key-value pairs - key=${line%%=*} - value=${line#*=} - key=$(echo $key | xargs) # Trim key - value=$(echo $value | xargs) # Trim value - - # Store in associative array with 'section_key' format - composite_key="${current_section}_${key}" - config[$composite_key]="$value" - fi - done < "$ini_path" - - # echo "Configuration loaded." -} diff --git a/include/qsgen2/lang/en_UK b/include/qsgen2/lang/en_UK deleted file mode 100644 index c30f7f3..0000000 --- a/include/qsgen2/lang/en_UK +++ /dev/null @@ -1,217 +0,0 @@ -# Quick Site Generator 2 - English Language File -# This file contains all user-facing strings for the application - -# Error Messages -error.missing_dependencies = "Missing required dependencies: %s" -error.config_validation_failed = "Configuration validation failed. Please check your configuration files." -error.config_missing_key = "Missing required configuration: %s" -error.invalid_url = "site_url must start with http:// or https://" -error.directory_not_found = "Directory does not exist: %s" -error.theme_not_found = "Theme directory not found: %s" -error.theme_config_not_found = "Theme configuration not found: %s" -error.theme_config_creation_failed = "Failed to create theme configuration: %s" -error.config_parse = "Failed to parse config file: %s" -error.invalid_path = "Invalid path: %s" -error.write_failed = "Failed to write to temporary file: %s" -error.move_failed = "Failed to move temporary file to: %s" -error.config_load_failed = "Failed to load configuration file: %s" -error.config_not_found = "No valid configuration file found." -error.create_blog_index_failed = "Failed to create blog index at: %s" -error.create_sample_post_failed = "Failed to create sample blog post at: %s" -error.create_sample_page_failed = "Failed to create sample page at: %s" -error.engine_not_found = "Engine not found or not executable: %s" -error.unknown_generator = "Unknown generator: %s" -error.unknown_option = "Unknown option: %s" -error.directory_not_empty = "Directory '%s' already exists and is not empty." -error.theme_creation_failed = "Failed to create theme: %s" -error.config_creation_failed = "Failed to create configuration file: %s" -error.directory_creation_failed = "Failed to create directory: %s" -error.file_creation_failed = "Failed to create file: %s" -error.layout_creation_failed = "Failed to create layout file: %s" -error.stylesheet_creation_failed = "Failed to create stylesheet: %s" -error.script_creation_failed = "Failed to create script file: %s" - -# Warning Messages -warning.optional_dependency = "Optional tool '%s' is required for %s but not found" -warning.dependency_version = "%s version %s is below the recommended version %s" -warning.legacy_config = "Using legacy config file. Consider renaming '%s' to 'site.conf'" -warning.git_repo = "Warning: Running in a git repository directory. Make sure this is intended." -warning.outdated_dependencies = "Some dependencies are outdated:" - -# Info Messages -info.legacy_config = "Warning: Using legacy '%s' file. Consider renaming to 'site.conf'" -info.legacy_config_used = "Using legacy config file. Consider renaming 'config' to 'site.conf'" -info.config_help = "Please create 'site.conf' in your project directory." -info.config_template = "You can use 'config.example' as a template." -info.git_repo_help = "If you want to generate the site, run from the project root directory." -info.usage = "Usage: %s [options]" -info.engine_usage = "Usage: _run_engine " -info.creating_blog_index = "Creating blog index file..." -info.creating_sample_post = "Creating sample blog post..." -info.creating_sample_page = "Creating sample page..." -info.setting_up_project = "Setting up project structure..." -info.creating_directories = "Creating project directories..." -info.initializing_blog = "Initializing blog..." -info.initializing_pages = "Initializing pages..." -info.initializing_theme = "Initializing theme..." -info.initializing_config = "Initializing configuration..." -info.initializing_complete = "Initialization complete!" -info.initializing_aborted = "Initialization aborted." -info.use_force_option = "Use --force to overwrite the existing directory." -info.get_started_instructions = "To get started" -info.happy_coding = "Happy coding!" -info.initializing_project = "Initializing project..." -info.initializing_blog_cache = "Initializing blog cache..." -info.initializing_pages_cache = "Initializing pages cache..." - -# Debug Messages -debug.loading_config = "Loading config file: %s" -debug.loaded_config = "=== Loaded Configuration ===" -debug.config_value = "%s: %s" -debug.config_end = "===========================" -debug.raw_config = "=== Raw Config File ===" -debug.raw_config_end = "======================" -debug.blog_cache_update = "Updating blog cache at %s" -debug.blog_cache_bytes = "Blog cache updated with %d bytes" -debug.blog_cache_loading = "Loading blog index from cache" -debug.blog_cache_stale_new = "Blog cache stale: New or updated blogs detected" -debug.blog_cache_stale_missing = "Blog cache stale: Cache file does not exist" -debug.blog_cache_stale_old = "Blog cache stale: Cache is older than 1 hour" -debug.blog_cache_fresh = "Blog cache is fresh" -debug.pages_cache_update = "Updating pages cache at %s" -debug.pages_cache_bytes = "Pages cache updated with %d bytes" -debug.pages_cache_loading = "Loading pages index from cache" -debug.pages_cache_stale_new = "Pages cache stale: New or updated pages detected" -debug.pages_cache_stale_missing = "Pages cache stale: Cache file does not exist" -debug.pages_cache_stale_old = "Pages cache stale: Cache is older than 1 hour" -debug.pages_cache_fresh = "Pages cache is fresh" - -# Blog Messages -blog.not_found = "No blog files found." -blog.generating = "Generating blog" -blog.no_template = "Unable to find the blog template: %s" -blog.cache_updated = "Blog cache updated" -blog.cache_loading = "Loading blog cache" -blog.cache_stale = "Blog cache is stale, rebuilding..." -blog.cache_fresh = "Blog cache is fresh" -blog.post_updated = "Updated blog post: %s" -blog.post_skipped = "Skipped (no changes): %s" -blog.post_error = "Error processing blog post: %s" - -# Blog Generation Messages -blog.hello_world_title = "Hello, World!" -blog.published_on = "Published on" -blog.welcome_message = "Welcome to your new blog! This is a sample blog post." -blog.getting_started = "Getting Started" -blog.edit_this_post = "You can edit this post at %s" -blog.features = "Features" -blog.feature_markdown = "Markdown support" -blog.feature_easy_customize = "Easy to customize" -blog.feature_fast_lightweight = "Fast and lightweight" -blog.next_steps = "Next Steps" -blog.step_edit_post = "Edit this post" -blog.step_add_posts = "Add more posts" -blog.step_customize_theme = "Customize your theme" -blog.step_publish_site = "Publish your site" -blog.happy_blogging = "Happy blogging!" -blog.latest_posts = "Latest Posts" -blog.sample_post = "Blog Post" -blog.categories = "Categories" -blog.sample_category = "Category" -blog.archives = "Archives" -blog.tags = "Tags" -blog.about = "About" -blog.about_text = "This is a sample blog index page. You can edit it at %s" - -# Page Generation Messages -page.about_me_title = "About Me" -page.welcome_title = "Welcome to My Site" -page.welcome_message = "This is a sample about page. You can edit it at %s" -page.my_story_title = "My Story" -page.my_story_content = "I'm a passionate developer who loves creating amazing websites with qsgen2!" -page.skills_title = "Skills" -page.skill_webdev = "Web Development" -page.skill_design = "Design" -page.skill_opensource = "Open Source" -page.contact_title = "Contact" -page.contact_content = "You can reach me at: email@example.com" -page.about_site_title = "About This Site" -page.about_site_content = "This site was built with [qsgen2](https://github.com/kekePower/qsgen2)." - -# Success Messages -success.config_loaded = "Configuration loaded successfully" -success.build_complete = "Build completed successfully" -success.blog_index_created = "Created blog index at: %s" -success.sample_post_created = "Created sample blog post at: %s" -success.sample_page_created = "Created sample page at: %s" -success.project_initialized = "Project initialized successfully!" -success.theme_initialized = "Theme initialized successfully!" -success.config_initialized = "Configuration file created successfully!" - -# System Messages -system.created_by = "- Created by kekePower - 2018-%s" -system.see_help = "- See '%s help' for more information." - -# List Messages -list.pages_not_found = "_list_pages: No Pages found with ext %s" -list.pages_adding = "_list_pages: Adding file to array: %s" -list.blogs_not_found = "_list_blogs: No blog files found." -list.blogs_adding = "_list_blogs: Adding file to array: %s" - -# Blog Cache Messages -blog_cache.hash = "_blog_cache: HASH VALUE:" -blog_cache.current = "1. _blog_cache:" -blog_cache.cache_file = "2. _blog_cache: current_cache:" -blog_cache.new_cache = "3. _blog_cache: new_cache_file:" -blog_cache.new_current = "4. _blog_cache: new_current_cache:" - -# Pages Cache Messages -page_cache.hash = "PAGES HASH VALUE:" -page_cache.current = "1. pages_cache:" -page_cache.cache_file = "2. _pages_cache: current_cache:" -page_cache.pages_file = "2. _pages_cache: pages_file:" - -# Navigation -nav.home = "Home" -nav.blog = "Blog" -nav.about = "About" - -# Footer -footer.all_rights_reserved = "All rights reserved." - -# Configuration -config.site_config_title = "Site Configuration" -config.theme_config_title = "Theme Configuration" -config.site_name_default = "My Awesome Site" -config.site_tagline_default = "A static site generated with qsgen2" -config.site_description_default = "This is my awesome static site" -config.your_name = "Your Name" -config.theme_description = "A custom theme for qsgen2" -config.theme_files_title = "Theme files (relative to theme directory)" - -# CSS and JavaScript -css.main_styles = "Main Styles" -js.main_javascript = "Main JavaScript" -js.console_message = "Hello from qsgen2!" -js.add_custom_javascript = "Add any custom JavaScript here" -js.your_code_here = "Your code here" - -# Last Updated Messages -last_updated.setting = "_last_updated: Setting date and version in footer" -last_updated.file_not_found = "_f_last_updated: File %s not found." - -# Pages Messages -pages.generating = "Generating Pages" -pages.none = "* You do not have any pages *" -pages.no_template = "Unable to find the Pages template: %s" - -# Pandoc Messages -pandoc.install = "Please install Pandoc." -pandoc.download = "https://github.com/jgm/pandoc/releases" - -# Generator Messages -generator.not_found = "No valid generator found. Are you sure you've selected the correct generator in 'config'?" - -# Build Messages -build.forced = "- Forced Update: Generating Everything" -build.using_engine = "Using the %s -engine for files:" diff --git a/include/qsgen2/lang/en_US b/include/qsgen2/lang/en_US deleted file mode 100644 index c30f7f3..0000000 --- a/include/qsgen2/lang/en_US +++ /dev/null @@ -1,217 +0,0 @@ -# Quick Site Generator 2 - English Language File -# This file contains all user-facing strings for the application - -# Error Messages -error.missing_dependencies = "Missing required dependencies: %s" -error.config_validation_failed = "Configuration validation failed. Please check your configuration files." -error.config_missing_key = "Missing required configuration: %s" -error.invalid_url = "site_url must start with http:// or https://" -error.directory_not_found = "Directory does not exist: %s" -error.theme_not_found = "Theme directory not found: %s" -error.theme_config_not_found = "Theme configuration not found: %s" -error.theme_config_creation_failed = "Failed to create theme configuration: %s" -error.config_parse = "Failed to parse config file: %s" -error.invalid_path = "Invalid path: %s" -error.write_failed = "Failed to write to temporary file: %s" -error.move_failed = "Failed to move temporary file to: %s" -error.config_load_failed = "Failed to load configuration file: %s" -error.config_not_found = "No valid configuration file found." -error.create_blog_index_failed = "Failed to create blog index at: %s" -error.create_sample_post_failed = "Failed to create sample blog post at: %s" -error.create_sample_page_failed = "Failed to create sample page at: %s" -error.engine_not_found = "Engine not found or not executable: %s" -error.unknown_generator = "Unknown generator: %s" -error.unknown_option = "Unknown option: %s" -error.directory_not_empty = "Directory '%s' already exists and is not empty." -error.theme_creation_failed = "Failed to create theme: %s" -error.config_creation_failed = "Failed to create configuration file: %s" -error.directory_creation_failed = "Failed to create directory: %s" -error.file_creation_failed = "Failed to create file: %s" -error.layout_creation_failed = "Failed to create layout file: %s" -error.stylesheet_creation_failed = "Failed to create stylesheet: %s" -error.script_creation_failed = "Failed to create script file: %s" - -# Warning Messages -warning.optional_dependency = "Optional tool '%s' is required for %s but not found" -warning.dependency_version = "%s version %s is below the recommended version %s" -warning.legacy_config = "Using legacy config file. Consider renaming '%s' to 'site.conf'" -warning.git_repo = "Warning: Running in a git repository directory. Make sure this is intended." -warning.outdated_dependencies = "Some dependencies are outdated:" - -# Info Messages -info.legacy_config = "Warning: Using legacy '%s' file. Consider renaming to 'site.conf'" -info.legacy_config_used = "Using legacy config file. Consider renaming 'config' to 'site.conf'" -info.config_help = "Please create 'site.conf' in your project directory." -info.config_template = "You can use 'config.example' as a template." -info.git_repo_help = "If you want to generate the site, run from the project root directory." -info.usage = "Usage: %s [options]" -info.engine_usage = "Usage: _run_engine " -info.creating_blog_index = "Creating blog index file..." -info.creating_sample_post = "Creating sample blog post..." -info.creating_sample_page = "Creating sample page..." -info.setting_up_project = "Setting up project structure..." -info.creating_directories = "Creating project directories..." -info.initializing_blog = "Initializing blog..." -info.initializing_pages = "Initializing pages..." -info.initializing_theme = "Initializing theme..." -info.initializing_config = "Initializing configuration..." -info.initializing_complete = "Initialization complete!" -info.initializing_aborted = "Initialization aborted." -info.use_force_option = "Use --force to overwrite the existing directory." -info.get_started_instructions = "To get started" -info.happy_coding = "Happy coding!" -info.initializing_project = "Initializing project..." -info.initializing_blog_cache = "Initializing blog cache..." -info.initializing_pages_cache = "Initializing pages cache..." - -# Debug Messages -debug.loading_config = "Loading config file: %s" -debug.loaded_config = "=== Loaded Configuration ===" -debug.config_value = "%s: %s" -debug.config_end = "===========================" -debug.raw_config = "=== Raw Config File ===" -debug.raw_config_end = "======================" -debug.blog_cache_update = "Updating blog cache at %s" -debug.blog_cache_bytes = "Blog cache updated with %d bytes" -debug.blog_cache_loading = "Loading blog index from cache" -debug.blog_cache_stale_new = "Blog cache stale: New or updated blogs detected" -debug.blog_cache_stale_missing = "Blog cache stale: Cache file does not exist" -debug.blog_cache_stale_old = "Blog cache stale: Cache is older than 1 hour" -debug.blog_cache_fresh = "Blog cache is fresh" -debug.pages_cache_update = "Updating pages cache at %s" -debug.pages_cache_bytes = "Pages cache updated with %d bytes" -debug.pages_cache_loading = "Loading pages index from cache" -debug.pages_cache_stale_new = "Pages cache stale: New or updated pages detected" -debug.pages_cache_stale_missing = "Pages cache stale: Cache file does not exist" -debug.pages_cache_stale_old = "Pages cache stale: Cache is older than 1 hour" -debug.pages_cache_fresh = "Pages cache is fresh" - -# Blog Messages -blog.not_found = "No blog files found." -blog.generating = "Generating blog" -blog.no_template = "Unable to find the blog template: %s" -blog.cache_updated = "Blog cache updated" -blog.cache_loading = "Loading blog cache" -blog.cache_stale = "Blog cache is stale, rebuilding..." -blog.cache_fresh = "Blog cache is fresh" -blog.post_updated = "Updated blog post: %s" -blog.post_skipped = "Skipped (no changes): %s" -blog.post_error = "Error processing blog post: %s" - -# Blog Generation Messages -blog.hello_world_title = "Hello, World!" -blog.published_on = "Published on" -blog.welcome_message = "Welcome to your new blog! This is a sample blog post." -blog.getting_started = "Getting Started" -blog.edit_this_post = "You can edit this post at %s" -blog.features = "Features" -blog.feature_markdown = "Markdown support" -blog.feature_easy_customize = "Easy to customize" -blog.feature_fast_lightweight = "Fast and lightweight" -blog.next_steps = "Next Steps" -blog.step_edit_post = "Edit this post" -blog.step_add_posts = "Add more posts" -blog.step_customize_theme = "Customize your theme" -blog.step_publish_site = "Publish your site" -blog.happy_blogging = "Happy blogging!" -blog.latest_posts = "Latest Posts" -blog.sample_post = "Blog Post" -blog.categories = "Categories" -blog.sample_category = "Category" -blog.archives = "Archives" -blog.tags = "Tags" -blog.about = "About" -blog.about_text = "This is a sample blog index page. You can edit it at %s" - -# Page Generation Messages -page.about_me_title = "About Me" -page.welcome_title = "Welcome to My Site" -page.welcome_message = "This is a sample about page. You can edit it at %s" -page.my_story_title = "My Story" -page.my_story_content = "I'm a passionate developer who loves creating amazing websites with qsgen2!" -page.skills_title = "Skills" -page.skill_webdev = "Web Development" -page.skill_design = "Design" -page.skill_opensource = "Open Source" -page.contact_title = "Contact" -page.contact_content = "You can reach me at: email@example.com" -page.about_site_title = "About This Site" -page.about_site_content = "This site was built with [qsgen2](https://github.com/kekePower/qsgen2)." - -# Success Messages -success.config_loaded = "Configuration loaded successfully" -success.build_complete = "Build completed successfully" -success.blog_index_created = "Created blog index at: %s" -success.sample_post_created = "Created sample blog post at: %s" -success.sample_page_created = "Created sample page at: %s" -success.project_initialized = "Project initialized successfully!" -success.theme_initialized = "Theme initialized successfully!" -success.config_initialized = "Configuration file created successfully!" - -# System Messages -system.created_by = "- Created by kekePower - 2018-%s" -system.see_help = "- See '%s help' for more information." - -# List Messages -list.pages_not_found = "_list_pages: No Pages found with ext %s" -list.pages_adding = "_list_pages: Adding file to array: %s" -list.blogs_not_found = "_list_blogs: No blog files found." -list.blogs_adding = "_list_blogs: Adding file to array: %s" - -# Blog Cache Messages -blog_cache.hash = "_blog_cache: HASH VALUE:" -blog_cache.current = "1. _blog_cache:" -blog_cache.cache_file = "2. _blog_cache: current_cache:" -blog_cache.new_cache = "3. _blog_cache: new_cache_file:" -blog_cache.new_current = "4. _blog_cache: new_current_cache:" - -# Pages Cache Messages -page_cache.hash = "PAGES HASH VALUE:" -page_cache.current = "1. pages_cache:" -page_cache.cache_file = "2. _pages_cache: current_cache:" -page_cache.pages_file = "2. _pages_cache: pages_file:" - -# Navigation -nav.home = "Home" -nav.blog = "Blog" -nav.about = "About" - -# Footer -footer.all_rights_reserved = "All rights reserved." - -# Configuration -config.site_config_title = "Site Configuration" -config.theme_config_title = "Theme Configuration" -config.site_name_default = "My Awesome Site" -config.site_tagline_default = "A static site generated with qsgen2" -config.site_description_default = "This is my awesome static site" -config.your_name = "Your Name" -config.theme_description = "A custom theme for qsgen2" -config.theme_files_title = "Theme files (relative to theme directory)" - -# CSS and JavaScript -css.main_styles = "Main Styles" -js.main_javascript = "Main JavaScript" -js.console_message = "Hello from qsgen2!" -js.add_custom_javascript = "Add any custom JavaScript here" -js.your_code_here = "Your code here" - -# Last Updated Messages -last_updated.setting = "_last_updated: Setting date and version in footer" -last_updated.file_not_found = "_f_last_updated: File %s not found." - -# Pages Messages -pages.generating = "Generating Pages" -pages.none = "* You do not have any pages *" -pages.no_template = "Unable to find the Pages template: %s" - -# Pandoc Messages -pandoc.install = "Please install Pandoc." -pandoc.download = "https://github.com/jgm/pandoc/releases" - -# Generator Messages -generator.not_found = "No valid generator found. Are you sure you've selected the correct generator in 'config'?" - -# Build Messages -build.forced = "- Forced Update: Generating Everything" -build.using_engine = "Using the %s -engine for files:" diff --git a/include/qsgen2/lang/es_ES b/include/qsgen2/lang/es_ES deleted file mode 100644 index 9a0e825..0000000 --- a/include/qsgen2/lang/es_ES +++ /dev/null @@ -1,207 +0,0 @@ -# Generador Rápido de Sitios 2 - Archivo de idioma español -# Este archivo contiene todas las cadenas visibles para el usuario de la aplicación - -# Mensajes de error -error.missing_dependencies = "Faltan dependencias requeridas: %s" -error.config_validation_failed = "Error en la validación de la configuración. Por favor, verifique sus archivos de configuración." -error.config_missing_key = "Falta la configuración requerida: %s" -error.invalid_url = "site_url debe comenzar con http:// o https://" -error.directory_not_found = "El directorio no existe: %s" -error.theme_not_found = "Directorio del tema no encontrado: %s" -error.theme_config_not_found = "Configuración del tema no encontrada: %s" -error.theme_config_creation_failed = "Error al crear la configuración del tema: %s" -error.config_parse = "Error al analizar el archivo de configuración: %s" -error.invalid_path = "Ruta no válida: %s" -error.write_failed = "Error al escribir en el archivo temporal: %s" -error.move_failed = "Error al mover el archivo temporal a: %s" -error.config_load_failed = "Error al cargar el archivo de configuración: %s" -error.config_not_found = "No se encontró ningún archivo de configuración válido." -error.create_blog_index_failed = "Error al crear el índice del blog en: %s" -error.create_sample_post_failed = "Error al crear la entrada de blog de ejemplo en: %s" -error.create_sample_page_failed = "Error al crear la página de ejemplo en: %s" -error.engine_not_found = "Motor no encontrado o no ejecutable: %s" -error.unknown_generator = "Generador desconocido: %s" -error.unknown_option = "Opción desconocida: %s" -error.directory_not_empty = "El directorio '%s' ya existe y no está vacío." -error.theme_creation_failed = "Error al crear el tema: %s" -error.config_creation_failed = "Error al crear el archivo de configuración: %s" -error.directory_creation_failed = "Error al crear el directorio: %s" -error.file_creation_failed = "Error al crear el archivo: %s" -error.layout_creation_failed = "Error al crear el archivo de diseño: %s" -error.stylesheet_creation_failed = "Error al crear la hoja de estilos: %s" -error.script_creation_failed = "Error al crear el archivo de script: %s" - -# Mensajes de advertencia -warning.optional_dependency = "La herramienta opcional '%s' es necesaria para %s pero no se encontró" -warning.dependency_version = "La versión %s de %s es inferior a la versión recomendada %s" -warning.legacy_config = "Usando archivo de configuración heredado. Considere renombrar '%s' a 'site.conf'" -warning.git_repo = "Advertencia: Ejecutando en un directorio de repositorio git. Asegúrese de que es intencionado." -warning.outdated_dependencies = "Algunas dependencias están desactualizadas:" - -# Mensajes informativos -info.legacy_config = "Advertencia: Usando archivo heredado '%s'. Considere renombrarlo a 'site.conf'" -info.legacy_config_used = "Usando archivo de configuración heredado. Considere renombrar 'config' a 'site.conf'" -info.config_help = "Por favor, cree un archivo 'site.conf' en el directorio de su proyecto." -info.config_template = "Puede usar 'config.example' como plantilla." -info.git_repo_help = "Si desea generar el sitio, ejecútelo desde el directorio raíz del proyecto." -info.usage = "Uso: %s [opciones]" -info.engine_usage = "Uso: _run_engine " -info.creating_blog_index = "Creando archivo de índice del blog..." -info.creating_sample_post = "Creando entrada de blog de ejemplo..." -info.creating_sample_page = "Creando página de ejemplo..." -info.setting_up_project = "Configurando la estructura del proyecto..." -info.creating_directories = "Creando directorios del proyecto..." -info.initializing_blog = "Inicializando blog..." -info.initializing_pages = "Inicializando páginas..." -info.initializing_theme = "Inicializando tema..." -info.initializing_config = "Inicializando configuración..." -info.initializing_complete = "¡Inicialización completada!" -info.initializing_aborted = "Inicialización cancelada." -info.use_force_option = "Use --force para sobrescribir el directorio existente." -info.get_started_instructions = "Para comenzar" -info.happy_coding = "¡Feliz programación!" -info.initializing_project = "Inicializando proyecto..." -info.initializing_blog_cache = "Inicializando caché del blog..." -info.initializing_pages_cache = "Inicializando caché de páginas..." - -# Mensajes de depuración -debug.loading_config = "Cargando archivo de configuración: %s" -debug.loaded_config = "=== Configuración Cargada ===" -debug.config_value = "%s: %s" -debug.config_end = "============================" -debug.raw_config = "=== Archivo de Configuración en Bruto ===" -debug.raw_config_end = "==================================" -debug.blog_cache_update = "Actualizando caché del blog en %s" -debug.blog_cache_bytes = "Caché del blog actualizado con %d bytes" -debug.blog_cache_loading = "Cargando índice del blog desde la caché" -debug.blog_cache_stale_new = "Caché del blog desactualizado: Se detectaron blogs nuevos o actualizados" -debug.blog_cache_stale_missing = "Caché del blog desactualizado: El archivo de caché no existe" -debug.blog_cache_stale_old = "Caché del blog desactualizado: La caché tiene más de 1 hora" -debug.blog_cache_fresh = "La caché del blog está actualizada" -debug.pages_cache_update = "Actualizando caché de páginas en %s" -debug.pages_cache_bytes = "Caché de páginas actualizado con %d bytes" -debug.pages_cache_loading = "Cargando índice de páginas desde la caché" -debug.pages_cache_stale_new = "Caché de páginas desactualizado: Se detectaron páginas nuevas o actualizadas" -debug.pages_cache_stale_missing = "Caché de páginas desactualizado: El archivo de caché no existe" -debug.pages_cache_stale_old = "Caché de páginas desactualizado: La caché tiene más de 1 hora" -debug.pages_cache_fresh = "La caché de páginas está actualizada" - -# Mensajes del Blog -blog.not_found = "No se encontraron archivos de blog." -blog.generating = "Generando blog" -blog.no_template = "No se pudo encontrar la plantilla del blog: %s" -blog.cache_updated = "Caché del blog actualizado" -blog.cache_loading = "Cargando caché del blog" -blog.cache_stale = "La caché del blog está desactualizada, reconstruyendo..." -blog.cache_fresh = "La caché del blog está actualizada" -blog.post_updated = "Entrada de blog actualizada: %s" -blog.post_skipped = "Omitido (sin cambios): %s" -blog.post_error = "Error al procesar la entrada del blog: %s" - -# Mensajes de Generación del Blog -blog.hello_world_title = "¡Hola, Mundo!" -blog.published_on = "Publicado el" -blog.welcome_message = "¡Bienvenido a tu nuevo blog! Esta es una entrada de blog de ejemplo." -blog.getting_started = "Comenzando" -blog.edit_this_post = "Puedes editar esta entrada en %s" -blog.features = "Características" -blog.feature_markdown = "Soporte para Markdown" -blog.feature_easy_customize = "Fácil de personalizar" -blog.feature_fast_lightweight = "Rápido y ligero" -blog.next_steps = "Próximos pasos" -blog.step_edit_post = "Editar esta entrada" -blog.step_add_posts = "Añadir más entradas" -blog.step_customize_theme = "Personalizar tu tema" -blog.step_publish_site = "Publicar tu sitio" -blog.happy_blogging = "¡Feliz blogueo!" -blog.latest_posts = "Últimas entradas" -blog.sample_post = "Entrada de blog" -blog.categories = "Categorías" -blog.sample_category = "Categoría" -blog.archives = "Archivos" -blog.tags = "Etiquetas" -blog.about = "Acerca de" -blog.about_text = "Esta es una página de índice de blog de ejemplo. Puedes editarla en %s" - -# Mensajes de Generación de Páginas -page.about_me_title = "Sobre Mí" -page.welcome_title = "Bienvenido a Mi Sitio" -page.welcome_message = "Esta es una página de ejemplo. Puedes editarla en %s" -page.my_story_title = "Mi Historia" -page.my_story_content = "¡Soy un desarrollador apasionado que adora crear sitios web increíbles con qsgen2!" -page.skills_title = "Habilidades" -page.skill_webdev = "Desarrollo Web" -page.skill_design = "Diseño" -page.skill_opensource = "Código Abierto" -page.contact_title = "Contacto" -page.contact_content = "Puedes contactarme en: email@example.com" -page.about_site_title = "Acerca de Este Sitio" -page.about_site_content = "Este sitio fue construido con [qsgen2](https://github.com/kekePower/qsgen2)." - -# Mensajes de Éxito -success.config_loaded = "Configuración cargada exitosamente" -success.build_complete = "Construcción completada exitosamente" -success.blog_index_created = "Índice del blog creado en: %s" -success.sample_post_created = "Entrada de blog de ejemplo creada en: %s" -success.sample_page_created = "Página de ejemplo creada en: %s" -success.project_initialized = "¡Proyecto inicializado exitosamente!" -success.theme_initialized = "¡Tema inicializado exitosamente!" -success.config_initialized = "¡Archivo de configuración creado exitosamente!" - -# Mensajes del Sistema -system.created_by = "- Creado por kekePower - 2018-%s" -system.see_help = "- Ver '%s help' para más información." - -# Mensajes de Lista -list.pages_not_found = "_list_pages: No se encontraron páginas con la extensión %s" -list.pages_adding = "_list_pages: Añadiendo archivo al array: %s" -list.blogs_not_found = "_list_blogs: No se encontraron archivos de blog." -list.blogs_adding = "_list_blogs: Añadiendo archivo al array: %s" - -# Navegación -nav.home = "Inicio" -nav.blog = "Blog" -nav.about = "Acerca de" - -# Pie de Página -footer.all_rights_reserved = "Todos los derechos reservados." - -# Configuración -config.site_config_title = "Configuración del Sitio" -config.theme_config_title = "Configuración del Tema" -config.site_name_default = "Mi Sitio Increíble" -config.site_tagline_default = "Un sitio estático generado con qsgen2" -config.site_description_default = "Este es mi increíble sitio estático" -config.your_name = "Tu Nombre" -config.theme_description = "Un tema personalizado para qsgen2" -config.theme_files_title = "Archivos del tema (relativo al directorio del tema)" - -# CSS y JavaScript -css.main_styles = "Estilos Principales" -js.main_javascript = "JavaScript Principal" -js.console_message = "¡Hola desde qsgen2!" -js.add_custom_javascript = "Añade cualquier JavaScript personalizado aquí" -js.your_code_here = "Tu código aquí" - -# Mensajes de Última Actualización -last_updated.setting = "_last_updated: Estableciendo fecha y versión en el pie de página" -last_updated.file_not_found = "_f_last_updated: Archivo %s no encontrado." - -# Mensajes de Páginas -pages.generating = "Generando Páginas" -pages.none = "* No tienes páginas *" -pages.no_template = "No se pudo encontrar la plantilla de páginas: %s" - -# Mensajes de Pandoc -pandoc.install = "Por favor, instala Pandoc." -pandoc.download = "https://github.com/jgm/pandoc/releases" - -# Mensajes del Generador -generator.not_found = "No se encontró un generador válido. ¿Estás seguro de que has seleccionado el generador correcto en 'config'?" -generator.using = "Usando generador: %s" -generator.execution_failed = "Error en la ejecución del generador: %s" -generator.execution_success = "Generador ejecutado exitosamente: %s" - -# Mensajes de Construcción -build.forced = "- Actualización forzada: Generando todo" -build.using_engine = "Usando el motor %s para archivos:" diff --git a/include/qsgen2/lang/fr_FR b/include/qsgen2/lang/fr_FR deleted file mode 100644 index 7773361..0000000 --- a/include/qsgen2/lang/fr_FR +++ /dev/null @@ -1,209 +0,0 @@ -# Générateur de Site Rapide 2 - Fichier de langue française -# Ce fichier contient toutes les chaînes visibles par l'utilisateur pour l'application - -# Messages d'erreur -error.missing_dependencies = "Dépendances requises manquantes : %s" -error.config_validation_failed = "Échec de la validation de la configuration. Veuillez vérifier vos fichiers de configuration." -error.config_missing_key = "Configuration requise manquante : %s" -error.invalid_url = "site_url doit commencer par http:// ou https://" -error.directory_not_found = "Le répertoire n'existe pas : %s" -error.theme_not_found = "Répertoire du thème introuvable : %s" -error.theme_config_not_found = "Configuration du thème introuvable : %s" -error.theme_config_creation_failed = "Échec de la création de la configuration du thème : %s" -error.config_parse = "Échec de l'analyse du fichier de configuration : %s" -error.invalid_path = "Chemin invalide : %s" -error.write_failed = "Échec de l'écriture dans le fichier temporaire : %s" -error.move_failed = "Échec du déplacement du fichier temporaire vers : %s" -error.config_load_failed = "Échec du chargement du fichier de configuration : %s" -error.config_not_found = "Aucun fichier de configuration valide trouvé." -error.create_blog_index_failed = "Échec de la création de l'index du blog à : %s" -error.create_sample_post_failed = "Échec de la création d'un exemple d'article de blog à : %s" -error.create_sample_page_failed = "Échec de la création d'une page exemple à : %s" -error.engine_not_found = "Moteur introuvable ou non exécutable : %s" -error.unknown_generator = "Générateur inconnu : %s" -error.unknown_option = "Option inconnue : %s" -error.directory_not_empty = "Le répertoire '%s' existe déjà et n'est pas vide." -error.theme_creation_failed = "Échec de la création du thème : %s" -error.config_creation_failed = "Échec de la création du fichier de configuration : %s" -error.directory_creation_failed = "Échec de la création du répertoire : %s" -error.file_creation_failed = "Échec de la création du fichier : %s" -error.layout_creation_failed = "Échec de la création du fichier de mise en page : %s" -error.stylesheet_creation_failed = "Échec de la création de la feuille de style : %s" -error.script_creation_failed = "Échec de la création du fichier de script : %s" - -# Messages d'avertissement -warning.optional_dependency = "L'outil optionnel '%s' est requis pour %s mais n'a pas été trouvé" -warning.dependency_version = "La version %s de %s est inférieure à la version recommandée %s" -warning.legacy_config = "Utilisation d'un fichier de configuration hérité. Envisagez de renommer '%s' en 'site.conf'" -warning.git_repo = "Attention : Exécution dans un répertoire de dépôt git. Assurez-vous que c'est intentionnel." -warning.outdated_dependencies = "Certaines dépendances ne sont pas à jour :" - -# Messages d'information -info.legacy_config = "Attention : Utilisation du fichier hérité '%s'. Envisagez de le renommer en 'site.conf'" -info.legacy_config_used = "Utilisation du fichier de configuration hérité. Envisagez de renommer 'config' en 'site.conf'" -info.config_help = "Veuillez créer un fichier 'site.conf' dans votre répertoire de projet." -info.config_template = "Vous pouvez utiliser 'config.example' comme modèle." -info.git_repo_help = "Si vous souhaitez générer le site, exécutez depuis le répertoire racine du projet." -info.usage = "Utilisation : %s [options]" -info.engine_usage = "Utilisation : _run_engine " -info.creating_blog_index = "Création du fichier d'index du blog..." -info.creating_sample_post = "Création d'un exemple d'article de blog..." -info.creating_sample_page = "Création d'une page exemple..." -info.setting_up_project = "Configuration de la structure du projet..." -info.creating_directories = "Création des répertoires du projet..." -info.initializing_blog = "Initialisation du blog..." -info.initializing_pages = "Initialisation des pages..." -info.initializing_theme = "Initialisation du thème..." -# Messages de débogage -debug.loading_config = "Chargement du fichier de configuration : %s" -debug.loaded_config = "=== Configuration Chargée ===" -debug.config_value = "%s : %s" -debug.config_end = "==========================" -debug.raw_config = "=== Fichier de Configuration Brut ===" -debug.raw_config_end = "================================" -debug.blog_cache_update = "Mise à jour du cache du blog à %s" -debug.blog_cache_bytes = "Cache du blog mis à jour avec %d octets" -debug.blog_cache_loading = "Chargement de l'index du blog depuis le cache" -debug.blog_cache_stale_new = "Cache du blog obsolète : Nouveaux blogs ou mises à jour détectés" -debug.blog_cache_stale_deleted = "Cache du blog obsolète : Blogs supprimés détectés" -debug.blog_cache_fresh = "Le cache du blog est à jour, reconstruction ignorée" -debug.blog_cache_rebuilding = "Reconstruction du cache du blog..." -debug.blog_cache_rebuilt = "Cache du blog reconstruit avec %d entrées" -debug.pages_cache_update = "Mise à jour du cache des pages à %s" -debug.pages_cache_bytes = "Cache des pages mis à jour avec %d octets" -debug.pages_cache_loading = "Chargement de l'index des pages depuis le cache" -debug.pages_cache_stale_new = "Cache des pages obsolète : Nouvelles pages ou mises à jour détectées" -debug.pages_cache_stale_deleted = "Cache des pages obsolète : Pages supprimées détectées" -debug.pages_cache_fresh = "Le cache des pages est à jour, reconstruction ignorée" -debug.pages_cache_rebuilding = "Reconstruction du cache des pages..." -debug.pages_cache_rebuilt = "Cache des pages reconstruit avec %d entrées" -debug.cache_hit = "Cache trouvé pour %s" -debug.cache_miss = "Cache manquant pour %s" -debug.cache_updated = "Cache mis à jour pour %s" -debug.cache_skipped = "Mise à jour du cache ignorée pour %s (aucun changement détecté)" -blog.cache_loading = "Chargement de l'index du blog depuis le cache" -blog.cache_stale = "Cache du blog obsolète, reconstruction..." -blog.cache_fresh = "Le cache du blog est à jour" -blog.post_updated = "Article de blog mis à jour : %s" -blog.post_skipped = "Ignoré (aucun changement) : %s" - -# Blog Messages -blog.not_found = "Aucun fichier de blog trouvé." -blog.generating = "Génération du blog" -blog.no_template = "Impossible de trouver le modèle de blog : %s" -blog.cache_updated = "Cache du blog mis à jour" -blog.cache_loading = "Chargement de l'index du blog depuis le cache" -blog.cache_stale = "Cache du blog obsolète, reconstruction..." -blog.cache_fresh = "Le cache du blog est à jour" -blog.post_updated = "Article de blog mis à jour : %s" -blog.post_skipped = "Ignoré (aucun changement) : %s" -blog.post_error = "Erreur lors du traitement de l'article de blog : %s" - -# Messages de Génération de Blog -blog.hello_world_title = "Bonjour le monde !" -blog.published_on = "Publié le" -blog.welcome_message = "Bienvenue sur votre nouveau blog ! Ceci est un exemple d'article de blog." -blog.getting_started = "Pour commencer" -blog.edit_this_post = "Vous pouvez modifier cet article à l'emplacement %s" -blog.features = "Fonctionnalités" -blog.feature_markdown = "Prise en charge du Markdown" -blog.feature_easy_customize = "Facile à personnaliser" -blog.feature_fast_lightweight = "Rapide et léger" -blog.next_steps = "Prochaines étapes" -blog.step_edit_post = "Modifier cet article" -blog.step_add_posts = "Ajouter plus d'articles" -blog.step_customize_theme = "Personnaliser votre thème" -blog.step_publish_site = "Publier votre site" -blog.happy_blogging = "Bon blogage !" -blog.latest_posts = "Derniers articles" -blog.sample_post = "Article de blog" -blog.categories = "Catégories" -blog.sample_category = "Catégorie" -blog.archives = "Archives" -blog.tags = "Étiquettes" -blog.about = "À propos" -blog.about_text = "Ceci est une page d'index de blog exemple. Vous pouvez la modifier à l'emplacement %s" - -# Messages de Génération de Pages -page.about_me_title = "À propos de moi" -page.welcome_title = "Bienvenue sur mon site" -page.welcome_message = "Ceci est une page À propos exemple. Vous pouvez la modifier à l'emplacement %s" -page.my_story_title = "Mon histoire" -page.my_story_content = "Je suis un développeur passionné qui adore créer des sites web incroyables avec qsgen2 !" -page.skills_title = "Compétences" -page.skill_webdev = "Développement Web" -page.skill_design = "Design" -page.skill_opensource = "Logiciel Libre" -page.contact_title = "Contact" -page.contact_content = "Vous pouvez me contacter à : email@exemple.com" -page.about_site_title = "À propos de ce site" -page.about_site_content = "Ce site a été construit avec [qsgen2](https://github.com/kekePower/qsgen2)." - -# Messages de Succès -success.config_loaded = "Configuration chargée avec succès" -success.build_complete = "Construction terminée avec succès" -success.blog_index_created = "Index du blog créé à l'emplacement : %s" -success.sample_post_created = "Exemple d'article de blog créé à l'emplacement : %s" -success.sample_page_created = "Page exemple créée à l'emplacement : %s" -success.project_initialized = "Projet initialisé avec succès !" -success.theme_initialized = "Thème initialisé avec succès !" -success.config_initialized = "Fichier de configuration créé avec succès !" - -# Messages Système -system.created_by = "- Créé par kekePower - 2018-%s" -system.see_help = "- Voir '%s help' pour plus d'informations." - -# Messages de Liste -list.pages_not_found = "_list_pages : Aucune page trouvée avec l'extension %s" -list.pages_adding = "_list_pages : Ajout du fichier au tableau : %s" -list.blogs_not_found = "_list_blogs : Aucun fichier de blog trouvé." -list.blogs_adding = "_list_blogs : Ajout du fichier au tableau : %s" - -# Navigation -nav.home = "Accueil" -nav.blog = "Blog" -nav.about = "À propos" - -# Pied de page -footer.all_rights_reserved = "Tous droits réservés." - -# Configuration -config.site_config_title = "Configuration du Site" -config.theme_config_title = "Configuration du Thème" -config.site_name_default = "Mon Super Site" -config.site_tagline_default = "Un site statique généré avec qsgen2" -config.site_description_default = "Voici mon super site statique" -config.your_name = "Votre Nom" -config.theme_description = "Un thème personnalisé pour qsgen2" -config.theme_files_title = "Fichiers du thème (relatif au répertoire du thème)" - -# CSS et JavaScript -css.main_styles = "Styles Principaux" -js.main_javascript = "JavaScript Principal" -js.console_message = "Bonjour depuis qsgen2 !" -js.add_custom_javascript = "Ajoutez votre code JavaScript personnalisé ici" -js.your_code_here = "Votre code ici" - -# Messages de Dernière Mise à Jour -last_updated.setting = "_last_updated : Définition de la date et de la version dans le pied de page" -last_updated.file_not_found = "_f_last_updated : Fichier %s non trouvé." - -# Pages Messages -pages.generating = "Génération des Pages" -pages.none = "* Vous n'avez aucune page *" -pages.no_template = "Impossible de trouver le modèle de page : %s" - -# Messages Pandoc -pandoc.install = "Veuillez installer Pandoc." -pandoc.download = "https://github.com/jgm/pandoc/releases" - -# Messages du Générateur -generator.not_found = "Aucun générateur valide trouvé. Êtes-vous sûr d'avoir sélectionné le bon générateur dans 'config' ?" -generator.using = "Utilisation du générateur : %s" -generator.not_found = "Générateur introuvable : %s" -generator.execution_failed = "Échec de l'exécution du générateur : %s" -generator.execution_success = "Générateur exécuté avec succès : %s" - -# Messages de Construction -build.forced = "- Mise à jour forcée : Génération complète" -build.using_engine = "Utilisation du moteur %s pour les fichiers :" diff --git a/include/qsgen2/lang/nb_NO b/include/qsgen2/lang/nb_NO deleted file mode 100644 index eb7bfc5..0000000 --- a/include/qsgen2/lang/nb_NO +++ /dev/null @@ -1,217 +0,0 @@ -# Quick Site Generator 2 - Norsk språkfil -# Denne filen inneholder alle brukervendte strenger for applikasjonen - -# Feilmeldinger -error.missing_dependencies = "Mangler påkrevde avhengigheter: %s" -error.config_validation_failed = "Validering av konfigurasjon feilet. Vennligst sjekk konfigurasjonsfilene dine." -error.config_missing_key = "Mangler påkrevd konfigurasjon: %s" -error.invalid_url = "site_url må starte med http:// eller https://" -error.directory_not_found = "Mappen finnes ikke: %s" -error.theme_not_found = "Temamappe ikke funnet: %s" -error.theme_config_not_found = "Temakonfigurasjon ikke funnet: %s" -error.theme_config_creation_failed = "Kunne ikke opprette temakonfigurasjon: %s" -error.config_parse = "Kunne ikke tolke konfigurasjonsfil: %s" -error.invalid_path = "Ugyldig sti: %s" -error.write_failed = "Kunne ikke skrive til midlertidig fil: %s" -error.move_failed = "Kunne ikke flytte midlertidig fil til: %s" -error.config_load_failed = "Kunne ikke laste konfigurasjonsfil: %s" -error.config_not_found = "Ingen gyldig konfigurasjonsfil funnet." -error.create_blog_index_failed = "Kunne ikke opprette bloggindeks på: %s" -error.create_sample_post_failed = "Kunne ikke opprette eksempelinnlegg på: %s" -error.create_sample_page_failed = "Kunne ikke opprette eksempelside på: %s" -error.engine_not_found = "Motor ikke funnet eller ikke kjørbar: %s" -error.unknown_generator = "Ukjent generator: %s" -error.unknown_option = "Ukjent alternativ: %s" -error.directory_not_empty = "Mappen '%s' finnes allerede og er ikke tom." -error.theme_creation_failed = "Kunne ikke opprette tema: %s" -error.config_creation_failed = "Kunne ikke opprette konfigurasjonsfil: %s" -error.directory_creation_failed = "Kunne ikke opprette mappe: %s" -error.file_creation_failed = "Kunne ikke opprette fil: %s" -error.layout_creation_failed = "Kunne ikke opprette layoutfil: %s" -error.stylesheet_creation_failed = "Kunne ikke opprette stilark: %s" -error.script_creation_failed = "Kunne ikke opprette scriptfil: %s" - -# Advarselsmeldinger -warning.optional_dependency = "Valgfritt verktøy '%s' kreves for %s, men ble ikke funnet" -warning.dependency_version = "%s versjon %s er lavere enn anbefalt versjon %s" -warning.legacy_config = "Bruker gammel konfigurasjonsfil. Vurder å endre navn på '%s' til 'site.conf'" -warning.git_repo = "Advarsel: Kjører i en git-mappe. Forsikre deg om at dette er meningen." -warning.outdated_dependencies = "Noen avhengigheter er utdaterte:" - -# Informasjonsmeldinger -info.legacy_config = "Advarsel: Bruker gammel '%s'-fil. Vurder å endre navn til 'site.conf'" -info.legacy_config_used = "Bruker gammel konfigurasjonsfil. Vurder å endre navn fra 'config' til 'site.conf'" -info.config_help = "Vennligst opprett 'site.conf' i prosjektmappen din." -info.config_template = "Du kan bruke 'config.example' som en mal." -info.git_repo_help = "Hvis du vil generere nettsiden, kjør fra prosjektets rotmappe." -info.usage = "Bruk: %s [alternativer]" -info.engine_usage = "Bruk: _run_engine " -info.creating_blog_index = "Oppretter bloggindeksfil..." -info.creating_sample_post = "Oppretter eksempelinnlegg..." -info.creating_sample_page = "Oppretter eksempelside..." -info.setting_up_project = "Setter opp prosjektstruktur..." -info.creating_directories = "Oppretter prosjektmapper..." -info.initializing_blog = "Initialiserer blogg..." -info.initializing_pages = "Initialiserer sider..." -info.initializing_theme = "Initialiserer tema..." -info.initializing_config = "Initialiserer konfigurasjon..." -info.initializing_complete = "Initialisering fullført!" -info.initializing_aborted = "Initialisering avbrutt." -info.use_force_option = "Bruk --force for å overskrive den eksisterende mappen." -info.get_started_instructions = "For å komme i gang" -info.happy_coding = "Lykke til med kodingen!" -info.initializing_project = "Initialiserer prosjekt..." -info.initializing_blog_cache = "Initialiserer blogg-mellomlager..." -info.initializing_pages_cache = "Initialiserer side-mellomlager..." - -# Feilsøkingsmeldinger -debug.loading_config = "Laster konfigurasjonsfil: %s" -debug.loaded_config = "=== Lastet Konfigurasjon ===" -debug.config_value = "%s: %s" -debug.config_end = "==========================" -debug.raw_config = "=== Rå Konfigurasjonsfil ===" -debug.raw_config_end = "========================" -debug.blog_cache_update = "Oppdaterer blogg-mellomlager på %s" -debug.blog_cache_bytes = "Blogg-mellomlager oppdatert med %d byte" -debug.blog_cache_loading = "Laster bloggindeks fra mellomlager" -debug.blog_cache_stale_new = "Blogg-mellomlager utdatert: Nye eller oppdaterte blogger oppdaget" -debug.blog_cache_stale_missing = "Blogg-mellomlager utdatert: Mellomlagerfilen finnes ikke" -debug.blog_cache_stale_old = "Blogg-mellomlager utdatert: Mellomlager er eldre enn 1 time" -debug.blog_cache_fresh = "Blogg-mellomlager er oppdatert" -debug.pages_cache_update = "Oppdaterer side-mellomlager på %s" -debug.pages_cache_bytes = "Side-mellomlager oppdatert med %d byte" -debug.pages_cache_loading = "Laster sideindeks fra mellomlager" -debug.pages_cache_stale_new = "Side-mellomlager utdatert: Nye eller oppdaterte sider oppdaget" -debug.pages_cache_stale_missing = "Side-mellomlager utdatert: Mellomlagerfilen finnes ikke" -debug.pages_cache_stale_old = "Side-mellomlager utdatert: Mellomlager er eldre enn 1 time" -debug.pages_cache_fresh = "Side-mellomlager er oppdatert" - -# Bloggmeldinger -blog.not_found = "Ingen bloggfiler funnet." -blog.generating = "Genererer blogg" -blog.no_template = "Kunne ikke finne bloggmalen: %s" -blog.cache_updated = "Blogg-mellomlager oppdatert" -blog.cache_loading = "Laster blogg-mellomlager" -blog.cache_stale = "Blogg-mellomlager er utdatert, bygger på nytt..." -blog.cache_fresh = "Blogg-mellomlager er oppdatert" -blog.post_updated = "Oppdatert blogginnlegg: %s" -blog.post_skipped = "Hoppet over (ingen endringer): %s" -blog.post_error = "Feil ved behandling av blogginnlegg: %s" - -# Blogg-genereringsmeldinger -blog.hello_world_title = "Hallo, verden!" -blog.published_on = "Publisert den" -blog.welcome_message = "Velkommen til din nye blogg! Dette er et eksempel på et blogginnlegg." -blog.getting_started = "Kom i gang" -blog.edit_this_post = "Du kan redigere dette innlegget på %s" -blog.features = "Funksjoner" -blog.feature_markdown = "Støtte for Markdown" -blog.feature_easy_customize = "Lett å tilpasse" -blog.feature_fast_lightweight = "Rask og lettvektig" -blog.next_steps = "Neste steg" -blog.step_edit_post = "Rediger dette innlegget" -blog.step_add_posts = "Legg til flere innlegg" -blog.step_customize_theme = "Tilpass temaet ditt" -blog.step_publish_site = "Publiser nettstedet ditt" -blog.happy_blogging = "Lykke til med bloggingen!" -blog.latest_posts = "Siste innlegg" -blog.sample_post = "Blogginnlegg" -blog.categories = "Kategorier" -blog.sample_category = "Kategori" -blog.archives = "Arkiv" -blog.tags = "Emneknagger" -blog.about = "Om" -blog.about_text = "Dette er en eksempelindeksside for bloggen. Du kan redigere den på %s" - -# Sidegenereringsmeldinger -page.about_me_title = "Om meg" -page.welcome_title = "Velkommen til nettstedet mitt" -page.welcome_message = "Dette er en eksempel 'om'-side. Du kan redigere den på %s" -page.my_story_title = "Min historie" -page.my_story_content = "Jeg er en lidenskapelig utvikler som elsker å lage fantastiske nettsteder med qsgen2!" -page.skills_title = "Ferdigheter" -page.skill_webdev = "Nettutvikling" -page.skill_design = "Design" -page.skill_opensource = "Åpen kildekode" -page.contact_title = "Kontakt" -page.contact_content = "Du kan nå meg på: epost@eksempel.no" -page.about_site_title = "Om dette nettstedet" -page.about_site_content = "Dette nettstedet er bygget med [qsgen2](https://github.com/kekePower/qsgen2)." - -# Suksessmeldinger -success.config_loaded = "Konfigurasjon lastet inn vellykket" -success.build_complete = "Bygging fullført vellykket" -success.blog_index_created = "Opprettet bloggindeks på: %s" -success.sample_post_created = "Opprettet eksempelblogginnlegg på: %s" -success.sample_page_created = "Opprettet eksempelside på: %s" -success.project_initialized = "Prosjektet er initialisert!" -success.theme_initialized = "Temaet er initialisert!" -success.config_initialized = "Konfigurasjonsfil opprettet!" - -# Blogg-mellomlager meldinger -blog_cache.hash = "_blog_cache: HASH VERDI:" -blog_cache.current = "1. _blog_cache:" -blog_cache.cache_file = "2. _blog_cache: current_cache:" -blog_cache.new_cache = "3. _blog_cache: new_cache_file:" -blog_cache.new_current = "4. _blog_cache: new_current_cache:" - -# Sider-mellomlager meldinger -page_cache.hash = "SIDER HASH VERDI:" -page_cache.current = "1. pages_cache:" -page_cache.cache_file = "2. _pages_cache: current_cache:" -page_cache.pages_file = "2. _pages_cache: pages_file:" - -# Systemmeldinger -system.created_by = "- Laget av kekePower - 2018-%s" -system.see_help = "- Se '%s help' for mer informasjon." - -# Listemeldinger -list.pages_not_found = "_list_pages: Ingen sider funnet med filendelse %s" -list.pages_adding = "_list_pages: Legger til fil i tabell: %s" -list.blogs_not_found = "_list_blogs: Ingen bloggfiler funnet." -list.blogs_adding = "_list_blogs: Legger til fil i tabell: %s" - -# Navigasjon -nav.home = "Hjem" -nav.blog = "Blogg" -nav.about = "Om" - -# Bunntekst -footer.all_rights_reserved = "Alle rettigheter reservert." - -# Konfigurasjon -config.site_config_title = "Nettstedsinnstillinger" -config.theme_config_title = "Temainnstillinger" -config.site_name_default = "Mitt fantastiske nettsted" -config.site_tagline_default = "Et statisk nettsted generert med qsgen2" -config.site_description_default = "Dette er mitt fantastiske statiske nettsted" -config.your_name = "Ditt navn" -config.theme_description = "Et egendefinert tema for qsgen2" -config.theme_files_title = "Temafiler (relativ til temamappe)" - -# CSS og JavaScript -css.main_styles = "Hovedstiler" -js.main_javascript = "Hoved-JavaScript" -js.console_message = "Hallo fra qsgen2!" -js.add_custom_javascript = "Legg til egendefinert JavaScript her" -js.your_code_here = "Din kode her" - -# Sist oppdatert-meldinger -last_updated.setting = "_last_updated: Setter dato og versjon i bunntekst" -last_updated.file_not_found = "_f_last_updated: Filen %s ble ikke funnet." - -# Pages Messages -pages.generating = "Genererer sider" -pages.none = "* Du har ingen sider *" -pages.no_template = "Kunne ikke finne sidemalen: %s" - -# Pandoc Messages -pandoc.install = "Please install Pandoc." -pandoc.download = "https://github.com/jgm/pandoc/releases" - -# Generator Messages -generator.not_found = "No valid generator found. Are you sure you've selected the correct generator in 'config'?" - -# Build Messages -build.forced = "- Forced Update: Generating Everything" -build.using_engine = "Using the %s -engine for files:" diff --git a/qsg2-square.png b/qsg2-square.png deleted file mode 100644 index e4f483e..0000000 Binary files a/qsg2-square.png and /dev/null differ diff --git a/qsgen3 b/qsgen3 deleted file mode 100755 index df659ab..0000000 --- a/qsgen3 +++ /dev/null @@ -1,2275 +0,0 @@ -#!/usr/bin/env zsh - -############################################################################### -############################################################################### -# -# Quick Site Generator 2 is a static website generator inspired by Nikola. -# It is written for the Z shell (zsh) because that's what I use and also because -# I like it better than Bash. -# -# This script is an almost complete rewrite of my old script because it became -# overly complicated and had way too many bugs, even though it worked on simple -# sites. -# -# https://github.com/kekePower/qsgen2/ -# -############################################################################### -############################################################################### - -VERSION="0.6.0" # Sun-2025-05-18 -QSGEN="Quick Site Generator 2" - -# Exit immediately if a command exits with a non-zero status -# Do not allow unset variables -# Exit if any command in a pipeline fails -set -euo pipefail - -# Set the default locale and handle all filenames correctly -LC_ALL=C -LANG=C -IFS=$' \n\t' - -# Set the umask to prevent world-writable files -umask 0022 - -# Enable advanced pattern matching and extended globbing -setopt extended_glob -setopt glob_star_short - -# Global associative arrays -typeset -gA config # Configuration parameters -typeset -gA config_cache # Cached configuration values -typeset -ga BLOG_META_STR_ARRAY # Blog metadata array -typeset -gA messages # Localized messages - -# Load messages with auto-detection and fallback to en_US -_load_messages() { - local lang_dir="${0:h}/include/qsgen2/lang" - - # Default to en_US if no language is specified - local lang="en_US" - - # 1. Try configured language first - if [[ -n "${SITE_LANG:-}" ]]; then - lang="$SITE_LANG" - # 2. Try auto-detected system language - elif command -v locale >/dev/null; then - local sys_lang=$(locale | grep '^LANG=' | cut -d= -f2 | cut -d. -f1 | tr -d '"') - if [[ -n "$sys_lang" && -f "$lang_dir/$sys_lang" ]]; then - lang="$sys_lang" - fi - fi - - # Initialize messages array - typeset -gA messages - - # Load the language file - if [[ -f "$lang_dir/$lang" ]]; then - # Source the language file which should define the messages array - source "$lang_dir/$lang" - _msg debug "Using language: $lang" - else - _msg error "Language file not found: $lang_dir/$lang" - exit 1 - fi - - # If no messages were loaded, initialize with default messages - if (( ${#messages[@]} == 0 )); then - _msg warning "No messages loaded from language file. Using default messages." - messages=( - [error.config_not_found]="Configuration file not found" - [error.invalid_config]="Invalid configuration" - [warning.legacy_config_used]="Using legacy config file. Consider renaming to 'site.conf'" - [info.create_config]="Please create 'site.conf' in your project directory." - # Add more default messages as needed - ) - fi -} - -# Get a localized message -_i18n() { - local key="$1" - shift - - # First try to get the message from the messages array - # The messages are stored in the format: messages[key]="value" - local msg="" - - # Handle different message types - case "$key" in - error.*|warning.*|info.*|debug.*|success.*|blog.*) - # Direct message key (e.g., error.config_not_found) - msg="${messages[$key]:-}" - ;; - *) - # Try to find the message by key first - msg="${messages[$key]:-}" - ;; - esac - - # If message is still empty, use the key as fallback - if [[ -z "$msg" ]]; then - msg="$key" - fi - - # Replace placeholders with provided arguments - local i=1 - for arg in "$@"; do - msg=${msg/\%s/"$arg"} - i=$((i + 1)) - done - - echo -n "$msg" -} - -# Original _msg function that handles the actual message output -_original_msg() { - local level="$1" - shift - - # Skip if quiet mode is enabled for this level - case "$level" in - debug) [[ -z "$DEBUG" ]] && return ;; - info) [[ -n "$QUIET" ]] && return ;; - esac - - # Output the message with appropriate formatting - case "$level" in - error) echo -e "\e[1;31m[ERROR] $*\e[0m" >&2 ;; - warning) echo -e "\e[1;33m[WARNING] $*\e[0m" >&2 ;; - success) echo -e "\e[1;32m[SUCCESS] $*\e[0m" ;; - info) echo -e "[INFO] $*" ;; - debug) echo -e "\e[2m[DEBUG] $*\e[0m" >&2 ;; - *) echo -e "[$level] $*" ;; - esac -} - -# Wrapper for _msg to support i18n -_msg() { - local level="$1" - shift - - if [[ "$1" == "i18n" ]]; then - shift - local key="$1" - shift - _original_msg "$level" "$(_i18n "$key" "$@")" - else - _original_msg "$level" "$@" - fi -} - -# Core required tools and their minimum versions -declare -A REQUIRED_TOOLS=( - [zsh]="5.8" - [grep]="3.0" - [sed]="4.5" - [find]="4.7" -) - -# Optional tools and their minimum versions -declare -A OPTIONAL_TOOLS=( - [pandoc]="2.0" # Only needed for markdown support -) - -# Check for required tools and their versions -_check_dependencies() { - local tool version min_version - local missing_deps=() - local outdated_deps=() - - # Check core required tools - for tool in "${(@k)REQUIRED_TOOLS}"; do - if ! command -v "$tool" &>/dev/null; then - missing_deps+=("$tool") - continue - fi - - min_version="${REQUIRED_TOOLS[$tool]}" - version=$(_get_tool_version "$tool") - - if [[ "$(_version_compare "$version" "$min_version")" == "<" ]]; then - outdated_deps+=("$tool (installed: $version, required: $min_version)") - fi - done - - # Check optional tools - for tool in "${(@k)OPTIONAL_TOOLS}"; do - if ! command -v "$tool" &>/dev/null; then - _msg warning i18n warning.optional_dependency "$tool" "${OPTIONAL_TOOLS[$tool]}" - continue - fi - - min_version="${OPTIONAL_TOOLS[$tool]}" - version=$(_get_tool_version "$tool") - - if [[ "$(_version_compare "$version" "$min_version")" == "<" ]]; then - _msg warning i18n warning.dependency_version "$tool" "$version" "$min_version" - fi - done - - # Report missing dependencies - if (( ${#missing_deps[@]} > 0 )); then - _msg error i18n error.missing_dependencies "${(j:, :)missing_deps}" - return 1 - fi - - # Report outdated dependencies - if (( ${#outdated_deps[@]} > 0 )); then - _msg warning i18n warning.outdated_dependencies - for dep in "${outdated_deps[@]}"; do - _msg warning "- $dep" - done - fi - - # Check optional tools based on configuration - if [[ "${config[project_generator]:-}" == "markdown" ]]; then - for tool in "${(@k)OPTIONAL_TOOLS}"; do - if ! command -v "$tool" &>/dev/null; then - _msg warning "Optional tool '$tool' is required for markdown support but not found" - continue - fi - - min_version="${OPTIONAL_TOOLS[$tool]}" - version=$(_get_tool_version "$tool") - - if [[ "$(_version_compare "$version" "$min_version")" == "<" ]]; then - _msg warning "$tool version $version is below the recommended version $min_version" - fi - done - fi - - if (( ${#missing_deps[@]} > 0 )); then - _msg error "Missing required dependencies: ${(j:, :)missing_deps}" - fi - - if (( ${#outdated_deps[@]} > 0 )); then - _msg warning "Some dependencies are outdated:" - printf ' - %s\n' "${outdated_deps[@]}" - fi - - if (( ${#missing_deps[@]} > 0 )); then - exit 1 - fi -} - -# Get version of a tool -_get_tool_version() { - local tool="$1" - case "$tool" in - zsh) - "$tool" --version &1 | grep -oE '[0-9]+\.[0-9]+(\.[0-9]+)?' | head -n1 - ;; - esac -} - -# Compare version numbers -_version_compare() { - local v1=("${(s/./)1}") - local v2=("${(s/./)2}") - local i - - for ((i=1; i <= ${#v1} || i <= ${#v2}; i++)); do - if (( ${v1[i]:-0} < ${v2[i]:-0} )); then - echo "<" - return 0 - elif (( ${v1[i]:-0} > ${v2[i]:-0} )); then - echo ">" - return 0 - fi - done - echo "=" -} - -# Enable/disable debug mode for the entire script -# Can be overridden in individual functions for targeted debugging -globaldebug=false - -# Load messages early -_load_messages - -# Set debug mode if needed -[[ -n "$DEBUG" ]] && globaldebug=true - -# Use Zsh fpath to set the path to some extra functions -fpath=(${HOME}/bin/include/common ${HOME}/bin/include/qsgen2/lang $fpath) -# In this case, let's load the 'include' function -autoload include -autoload zini - -# Including some colors to the script -include common/colors - -# Modern file reading function using zsh features -_read_file() { - local file="$1" - [[ -r "$file" ]] || return 1 - - # Use zsh's mapfile equivalent with proper error handling - local content - content="${(j: :f)$(<"$file")}" || return 1 - - # Remove trailing newline if present - echo -n "${content%$'\n'}" - return 0 -} - -echo "${magenta}${blue_bg} ${QSGEN} ${end}${bold_white}${blue_bg}${VERSION} ${end}" - -# Validate configuration values -_validate_config() { - local -a required=( - "site_name" "site_url" "site_theme" "site_root" "project_root" - "site_lang" "site_tagline" "site_description" - ) - - local valid=true - - # Check required fields - for key in "${required[@]}"; do - if [[ -z "${config[$key]:-}" ]]; then - _msg error i18n "error.missing_required_config" "${key}" - valid=false - fi - done - - # Validate URLs - if [[ -n "${config[site_url]:-}" ]]; then - if ! [[ "${config[site_url]}" =~ ^https?:// ]]; then - _msg error i18n "error.invalid_url_format" - valid=false - fi - fi - - # Validate directories - local -a dirs=("site_root" "project_root") - for dir in "${dirs[@]}"; do - if [[ -n "${config[$dir]:-}" && ! -d "${config[$dir]}" ]]; then - _msg error i18n "error.directory_not_found" "${config[$dir]}" - valid=false - fi - done - - # Validate theme - if [[ -n "${config[site_theme]:-}" && ! -d "${config[project_root]}/themes/${config[site_theme]}" ]]; then - _msg error i18n "error.theme_not_found" "${config[project_root]}/themes/${config[site_theme]}" - valid=false - fi - - # Load the theme configuration - local theme_conf="${config[project_root]}/themes/${config[site_theme]}/theme.conf" - if [[ -f "$theme_conf" ]]; then - source "$theme_conf" - _msg debug i18n "debug.theme_config_loaded" "$theme_conf" - else - _msg error i18n "error.theme_config_not_found" "$theme_conf" - exit 1 - fi - - if [[ "$valid" == false ]]; then - _msg error i18n "error.config_validation_failed" - exit 1 - fi -} - -# Load and validate configuration -_load_config() { - local config_file="$1" - if [[ -f "$config_file" ]]; then - if (${globaldebug}); then _msg debug i18n "debug.loading_config" "$config_file"; fi - if zini "$config_file"; then - return 0 - else - _msg error i18n "error.config_load_failed" "$config_file" - return 1 - fi - fi - return 1 -} - -# Check for, and source, the config file for this specific website -config_loaded=false -if _load_config "$(pwd)/site.conf"; then - config_loaded=true -elif _load_config "$(pwd)/config"; then - _msg warning i18n "warning.legacy_config_used" - config_loaded=true -else - _msg error i18n "error.config_not_found" - _msg info i18n "info.config_help" - _msg info i18n "info.config_template" - _msg info i18n "info.git_repo_help" - exit 1 -fi - -# Validate the loaded configuration -_validate_config - -# Set default values for optional parameters -config[parallel_jobs]="${config[parallel_jobs]:-$(nproc)}" -config[site_author]="${config[site_author]:-${USER}}" -config[site_timezone]="${config[site_timezone]:-$(date +%Z)}" - -# Ensure paths are absolute -if [[ -n "${config[site_root]:-}" && "${config[site_root]}" != /* ]]; then - config[site_root]="$(pwd)/${config[site_root]}" -fi - -if [[ -n "${config[project_root]:-}" && "${config[project_root]}" != /* ]]; then - config[project_root]="$(pwd)/${config[project_root]}" -fi - -# Safe file operations -_safe_path() { - # Resolve and validate a path to prevent directory traversal - # Usage: _safe_path "base/dir" "relative/path" - local base_dir="$1" - local target_path="$2" - - # Convert to absolute path - if [[ "$target_path" != /* ]]; then - target_path="$base_dir/$target_path" - fi - - # Normalize the path (resolve . and ..) - local normalized_path - normalized_path=$(realpath -m -- "$target_path" 2>/dev/null || echo "") - - # Ensure the path is within the base directory - if [[ -z "$normalized_path" || "$normalized_path" != "$base_dir"/* && "$normalized_path" != "$base_dir" ]]; then - _msg error i18n error.invalid_path "$target_path" - return 1 - fi - - echo "$normalized_path" - return 0 -} - -# Safe file writing with atomic operation -_safe_write() { - # Usage: _safe_write "content" "/path/to/file" - local content="$1" - local target_file="$2" - local tmp_file - - # Create parent directories if they don't exist - local dir_name - dir_name=$(dirname -- "$target_file") - mkdir -p -- "$dir_name" - - # Create a temporary file in the same directory for atomic write - tmp_file=$(mktemp -p "$dir_name" "${target_file##*/}.XXXXXXXXXX") - - # Write content to temporary file - echo -n "$content" > "$tmp_file" || { - _msg error i18n error.write_failed "$tmp_file" - rm -f -- "$tmp_file" - return 1 - } - - # Atomically move the file into place - mv -f -- "$tmp_file" "$target_file" || { - _msg error i18n error.move_failed "$tmp_file" "$target_file" - rm -f -- "$tmp_file" - return 1 - } - - return 0 -} - -# Debug: Show loaded configuration -if (${globaldebug}); then - _msg debug i18n debug.loaded_config - for key value in ${(kv)config}; do - _msg debug i18n debug.config_key_value "$key" "$value" - done - _msg debug i18n debug.config_end -fi - -# Check if we're in a git repository (but don't fail, just warn) -if git rev-parse --is-inside-work-tree &>/dev/null; then - _msg warning i18n warning.git_repo - _msg info i18n info.git_repo_help -fi - -# Create necessary directories if they don't exist -for dir in "${config[project_root]}/themes" "${config[project_root]}/pages" "${config[project_root]}/blog"; do - if [[ ! -d "$dir" ]]; then - mkdir -p "$dir" - _msg debug i18n debug.created_directory "$dir" - fi -done - -# Set up the appropriate engine and file extension -if [[ ${config[project_generator]} == "qstags" ]]; then - engine=_qstags - export file_ext="qst" -elif [[ ${config[project_generator]} == "markdown" ]]; then - if ! command -v pandoc &>/dev/null; then - _msg error i18n pandoc.install - _msg info i18n pandoc.download - exit 1 - else - engine="pandoc" - export file_ext="md" - fi -else - _msg error i18n generator.not_found - exit 1 -fi - -_msg debug i18n debug.using_engine "$engine" "$file_ext" - -function _generate_sample_page() { - # Usage: _generate_sample_page - # This function generates a sample page - - local sample_page="${config[project_root]}/pages/about.${file_ext}" - - if [[ ! -f "${sample_page}" ]]; then - _msg info i18n info.creating_sample_page - - _atomic_write "${sample_page}" "# $(i18n page.about_me_title) - -## $(i18n page.welcome_title) - -$(i18n page.welcome_message \"${sample_page}") - -## $(i18n page.my_story_title) - -$(i18n page.my_story_content) - -## $(i18n page.skills_title) - -- $(i18n page.skill_webdev) -- $(i18n page.skill_design) -- $(i18n page.skill_opensource) - -## $(i18n page.contact_title) - -$(i18n page.contact_content) - -## $(i18n page.about_site_title) - -$(i18n page.about_site_content)" - - if [[ $? -ne 0 ]]; then - _msg error i18n error.create_sample_page_failed "${sample_page}" - return 1 - fi - - _msg success i18n success.sample_page_created "${sample_page}" - else - _msg debug i18n debug.sample_page_exists "${sample_page}" - fi - - return 0 -} - -function _generate_sample_blog_post() { - # Usage: _generate_sample_blog_post - # This function generates a sample blog post - - local sample_post="${config[project_root]}/blog/hello-world.${file_ext}" - - if [[ ! -f "${sample_post}" ]]; then - _msg info i18n info.creating_sample_post - - _atomic_write "${sample_post}" "# $(i18n blog.hello_world_title) - -*$(i18n blog.published_on) $(date +'%Y-%m-%d')* - -$(i18n blog.welcome_message) - -## $(i18n blog.getting_started) - -$(i18n blog.edit_this_post \"${sample_post}") - -## $(i18n blog.features) - -- $(i18n blog.feature_markdown) -- $(i18n blog.feature_easy_customize) -- $(i18n blog.feature_fast_lightweight) - -## $(i18n blog.next_steps) - -1. $(i18n blog.step_edit_post) -2. $(i18n blog.step_add_posts) -3. $(i18n blog.step_customize_theme) -4. $(i18n blog.step_publish_site) - -$(i18n blog.happy_blogging)" - - if [[ $? -ne 0 ]]; then - _msg error i18n error.create_sample_post_failed "${sample_post}" - return 1 - fi - - _msg success i18n success.sample_post_created "${sample_post}" - else - _msg debug i18n debug.sample_post_exists "${sample_post}" - fi - - return 0 -} - -function _generate_blog_index() { - # Usage: _generate_blog_index - # This function generates the blog index page - - local blog_index="${config[project_root]}/blog/index.${file_ext}" - - if [[ ! -f "${blog_index}" ]]; then - _msg info i18n info.creating_blog_index - _atomic_write "${blog_index}" "# ${config[site_name]:-Blog} - -${config[site_tagline]:+> ${config[site_tagline]}} - -## $(i18n blog.latest_posts) - -- [$(i18n blog.sample_post) 1](blog/post1.${file_ext}) -- [$(i18n blog.sample_post) 2](blog/post2.${file_ext}) - -## $(i18n blog.categories) - -- [$(i18n blog.sample_category) 1](blog/category1.${file_ext}) -- [$(i18n blog.sample_category) 2](blog/category2.${file_ext}) - -## $(i18n blog.archives) - -- [2023](blog/2023.${file_ext}) -- [2024](blog/2024.${file_ext}) - -## $(i18n blog.tags) - -- [tag1](blog/tag1.${file_ext}) -- [tag2](blog/tag2.${file_ext}) - -## $(i18n blog.about) - -$(i18n blog.about_text \"${blog_index}")" - - if [[ $? -ne 0 ]]; then - _msg error i18n error.create_blog_index_failed "${blog_index}" - return 1 - fi - - _msg success i18n success.blog_index_created "${blog_index}" - else - _msg debug i18n debug.blog_index_exists "${blog_index}" - fi - - return 0 -} - -function _run_engine() { - # Usage: _run_engine - # This function runs the appropriate engine on the input file - - if [[ ${config[project_generator]} == "qstags" ]]; then - if [[ ! -x "$engine" ]]; then - _msg error i18n error.engine_not_found "$engine" - return 1 - fi - "$engine" "$1" - elif [[ ${config[project_generator]} == "markdown" ]]; then - if ! command -v "$engine" &>/dev/null; then - _msg error i18n error.engine_not_found "$engine" - return 1 - fi - "$engine" -f markdown -t html "$1" - else - _msg error i18n error.unknown_generator "${config[project_generator]}" - return 1 - fi -} - -if (${globaldebug}); then _msg debug "_qsgen2_msg_6"; fi - -builtin cd ${config[project_root]} - -# Loading Zsh modules -zmodload zsh/files -zmodload zsh/datetime -zmodload zsh/regex - -# Let's put these here for now. -export today=$(strftime "%Y-%m-%d - %T") -export blogdate=$(strftime "%a-%Y-%b-%d") - -# Let's create arrays of all the files we'll be working on - -function _list_pages() { - - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - # Initialize or clear the array to ensure it's empty before adding files - pages_file_array=() - - export no_pages_found=false - - # Temporarily set null_glob for this function - setopt local_options null_glob - - # Using an array to directly capture matching files - local -a pages_files=(*.${file_ext}) - - if (( ${#pages_files} == 0 )); then - if ${debug}; then _msg debug "${0:t}_msg_1" " ${file_ext}."; fi - export no_pages_found=true - return - else - for file in "${pages_files[@]}"; do - if ${debug}; then _msg debug "${0:t}_msg_2" " ${file}"; fi - pages_file_array+=("$file") - done - fi - -} - -function _list_blogs() { - - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - # Initialize or clear the blogs array to ensure it's empty before adding files - blogs_file_array=() - - export no_blogs_found=false - - # Temporarily set null_glob for this function - setopt local_options null_glob - - # Directly capture matching blog files into an array - local -a blog_files=(blog/*.blog(On)) - - if (( ${#blog_files[@]} == 0 )); then - if ${debug}; then _msg debug "${0:t}_msg_1"; fi - export no_blogs_found=true - return - else - for file in "${blog_files[@]}" - do - if ${debug}; then _msg debug "${0:t}_msg_2" " $file"; fi - blogs_file_array+=("$file") - done - fi - -} - - -# BLOG CACHE -blog_cache_file="${config[project_root]}/.blogindex.cache" - -function _update_blog_cache() { - # This function updates the blog cache with the current blog index content - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - if (${debug}) _msg debug "Updating blog cache at ${blog_cache_file}" - - # Get the current blog index content - local blog_index_content="$(<${config[project_root]}/blog/index.tmp.html)" - - # Store the content in the cache file - echo "${blog_index_content}" > "${blog_cache_file}" - - if (${debug}) _msg debug "Blog cache updated with ${#blog_index_content} bytes" -} - -function _load_blog_cache() { - # Loads the blog index from cache if it exists - if [[ -f "${blog_cache_file}" ]]; then - if (${debug}) _msg debug "Loading blog index from cache" - cat "${blog_cache_file}" - return 0 - fi - return 1 -} - -function _is_blog_cache_stale() { - # Returns 0 (success) if cache is stale or doesn't exist, 1 (failure) otherwise - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - # If we have new or updated blogs, cache is considered stale - if [[ ${new_updated_blogs} == "true" ]]; then - if (${debug}) _msg debug "Blog cache stale: New or updated blogs detected" - return 0 - fi - - # If cache file doesn't exist, it's stale - if [[ ! -f "${blog_cache_file}" ]]; then - if (${debug}) _msg debug "Blog cache stale: Cache file does not exist" - return 0 - fi - - # Check if cache is older than 1 hour (3600 seconds) - local cache_mtime=$(stat -c %Y "${blog_cache_file}" 2>/dev/null || echo 0) - local current_time=$(date +%s) - - if (( current_time - cache_mtime > 3600 )); then - if (${debug}) _msg debug "Blog cache stale: Cache is older than 1 hour" - return 0 - fi - - if (${debug}) _msg debug "Blog cache is fresh" - return 1 -} - -function _blog_cache() { - - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - _list_blogs - - # Create an associative array for the blog cache - typeset -gA config_cache - - # Load the existing blog cache - if [[ -f $blog_cache_file ]]; then - while IFS=':' read -r name hash; do - blog_cache[$name]=$hash - if (${debug}) _msg debug "${0:t}_msg_1" " ${blog_cache[${name}]}" - done < "$blog_cache_file" - fi - - # Initialize the array for storing blog files to process - make_blog_array=() - - # Process blog files - for blog_file in ${blogs_file_array[@]}; do - # Compute the current blog file hash - current_hash=$(md5sum "$blog_file" | awk '{print $1}') - - if (${debug}) _msg debug "${0:t}_msg_2" " ${blog_file}" - if (${debug}) _msg debug "${0:t}_msg_3" " ${current_hash}" - - # Check if the blog file is new or has changed - if [[ ${blog_cache[$blog_file]} != "$current_hash" ]]; then - if (${debug}) _msg debug "${0:t}_msg_4" " ${blog_file}" - if (${debug}) _msg debug "${0:t}_msg_5" " ${current_hash}" - # Blog file is new or has changed; add it to the processing array - make_blog_array+=("$blog_file") - - # Update the blog cache with the new hash - blog_cache[$blog_file]=$current_hash - fi - done - - # Rebuild the blog cache file from scratch - : >| "$blog_cache_file" # Truncate the file before writing - for name in "${(@k)blog_cache}"; do - echo "$name:${blog_cache[$name]}" >> "$blog_cache_file" - done - -} - - -# PAGES CACHE -# Returns the array pages_array() -function _pages_cache() { - - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - # Create an associative array for the pages cache - typeset -gA config_cache - - _list_pages - - # Load the existing pages cache - if [[ -f $pages_cache_file ]]; then - while IFS=':' read -r name hash; do - pages_cache[$name]=$hash - if (${debug}) _msg debug "${0:t}_msg_1" " ${pages_cache[${name}]}" - done < "$pages_cache_file" - fi - - # Initialize the array for storing pages files to process - pages_array=() - - # Process pages files - for file in ${pages_file_array[@]}; do - # Compute the current blog file hash - current_hash=$(md5sum "$file" | awk '{print $1}') - - if (${debug}) _msg debug "${0:t}_msg_2" " ${pages_cache[$file]}" - if (${debug}) _msg debug "${0:t}_msg_3" " current_cache: ${current_hash}" - - # Check if the pages file is new or has changed - if [[ ${pages_cache[$file]} != "$current_hash" ]]; then - if (${debug}) _msg debug "${0:t}_msg_4" " ${pages_cache[$file]}" - if (${debug}) _msg debug "${0:t}_msg_5" " current_cache: ${current_hash}" - - # Pages file is new or has changed; add it to the processing array - pages_array+=("$file") - - # Update the pages cache with the new hash - pages_cache[$file]=$current_hash - fi - done - - # Rebuild the pages cache file from scratch - : >| "$pages_cache_file" # Truncate the file before writing - for name in "${(@k)pages_cache}"; do - echo "$name:${pages_cache[$name]}" >> "$pages_cache_file" - done - -} - -function _last_updated() { - # This function updates #updated and #version tags in the provided string for buffers - - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - local upd_msg="Last updated ${today} by ${QSGEN} ${VERSION}" - - if (${debug}); then _msg debug "${0:t}_msg_1"; fi - if (${debug}); then _msg debug "${0:t}_msg_2" " ${upd_msg}"; fi - - local content="${1}" - - # Perform the replacements - local updated_content=$(echo "${content}" | sed \ - -e "s|#updated|${upd_msg}|") - - # Return the updated content - echo "${updated_content}" - -} - -function _f_last_updated() { - # Updates #updated and #version tags in the provided file using Zsh - - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - # local file_path="${1}" - local upd_msg="Last updated ${today} by ${QSGEN} ${VERSION}" - - if ${debug}; then - _msg debug "${0:t}_msg_1" " ${1}" - _msg debug "${0:t}_msg_2" " ${upd_msg}" - fi - - # Read the file content into a variable - local content="$(<${1})" - - # Perform the replacement - content="${content//#updated/${upd_msg}}" - - if [[ -f "${1}" ]]; then - sed -i -e "s|#updated|${upd_msg}|" "${1}" - else - _msg debug "${0:t}_msg_3" " '${1}' " "${0:t}_msg_3.1" - fi - -} - -function _file_to_lower() { - - local filename="${1}" - - # Replace spaces with dashes - filename="${filename// /-}" - - # Convert to lowercase and remove invalid characters - filename=$(echo "${filename}" | sed -e 's/^[^a-zA-Z0-9_.]+//g' -e 's/[^a-zA-Z0-9_-]+/-/g') - - echo ${filename} - -} - - -function _pages() { - # This function generates all the new and updated Pages - - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - _msg main "${0:t}_msg_3" - - # Load the cache for Pages - if (${debug}) _msg debug "${0:t}_msg_1" - _pages_cache - - if [[ ${no_pages_found} == "true" ]]; then - _msg sub "${0:t}_msg_1" - return - fi - - if (( ${#pages_array[@]} > 0 )); then - - # If pages_array is not empty, we do work - if (${debug}) _msg debug "${0:t}_msg_4" - - for pages_in_array in ${pages_array[@]} - do - if (${debug}) _msg debug "${0:t}_msg_5" - local pages=${config[project_root]}/themes/${config[site_theme]}/pages.tpl - - # Let's check if we can access the pages.tpl file. - # It not, exit script. - if [[ ! -f ${pages} ]]; then - _msg info "${0:t}_msg_6" " ${pages}" - exit - else - # Read template once - if (${debug}) _msg debug "${0:t}_msg_7" - local pages_tpl="$(<${pages})" - fi - - # _msg std " - ${pages_in_array%.*}.html" - # Read the file once - if (${debug}) _msg debug "${0:t}_msg_9" " ${pages_in_array}" - local page_content="$(<${pages_in_array})" - - # Grab the title from the Page - if (${debug}) _msg debug "${0:t}_msg_10" - if [[ ${config[project_generator]} == "native" ]]; then - while read -r line - do - if [[ "$line" =~ ^#title=(.*) ]]; then - local page_title=${match[1]} - break - #local page_title=$( echo ${page_content} | head -2 | grep \#title | cut -d= -f2 ) - fi - done <<< "$page_content" - elif [[ ${config[project_generator]} == "markdown" ]]; then - while IFS= read -r line - do - # Check if the line starts with '#' and capture the line - if [[ "$line" == \#* ]]; then - # Remove all leading '#' characters and the first space (if present) - local page_title="${line#\#}" # Remove the first '#' character - page_title="${page_title#\#}" # Remove the second '#' character if present - page_title="${page_title#"${page_title%%[![:space:]]*}"}" # Trim leading whitespace - break # Exit the loop after finding the first heading - fi - done <<< ${page_content} - fi - _msg std " - ${page_title}" - if (${debug}) _msg debug "${0:t}_msg_11" " ${page_title}" - - # Remove the #title line from the buffer. No longer needed. - if (${debug}) _msg debug "${0:t}_msg_12" - page_content=$( echo ${page_content} | grep -v \#title ) - - # HTML'ify the page content - if (${debug}) _msg debug "${0:t}_msg_13" " ${pages_in_array}" - page_content=$( _run_engine "$page_content" ) - # Look for links, images and videos and convert them if present. - if (${debug}) _msg debug "${0:t}_msg_14" - if [[ $( echo ${page_content} | grep \#link ) ]]; then - if (${debug}) _msg debug "${0:t}_msg_15" - page_content=$( _link "${page_content}" ) - fi - if [[ $( echo ${page_content} | grep \#showimg ) ]]; then - if (${debug}) _msg debug "${0:t}_msg_16" - page_content=$( _image "${page_content}" ) - fi - if [[ $( echo ${page_content} | grep \#linkimg ) ]]; then - if (${debug}) _msg debug "${0:t}_msg_17" - page_content=$( _linkimg "${page_content}" ) - fi - if [[ $( echo ${page_content} | grep \#ytvideo ) ]]; then - if (${debug}) _msg debug "${0:t}_msg_18" - page_content=$( _youtube "${page_content}" ) - fi - - # Replace every #pagetitle in pages_tpl - if (${debug}) _msg debug "${0:t}_msg_19" - pages_tpl=$(echo "${pages_tpl}" | perl -pe "s|#pagetitle|${page_title}|gs; s|#tagline|${config[site_tagline]}|gs; s|#sitename|${config[site_name]}|gs") - - if (${debug}) _msg debug "${0:t}_msg_20" - # Use awk for multi-line and special character handling - pages_tpl=$( awk -v new_body="$page_content" '{sub(/BODY/, new_body)} 1' <(echo "${pages_tpl}") ) - - # Replace #updated with today's date and #version with Name and Version to footer - if (${debug}) _msg debug "${0:t}_msg_21" - pages_tpl=$( _last_updated ${pages_tpl} ) - - # Always use lowercase for file names - if (${debug}) _msg debug "${0:t}_msg_22" - pages_title_lower=$( _file_to_lower "${pages_in_array}" ) - - # Clean up unused tags, if any - if (${debug}) _msg debug "${0:t}_msg_23" - pages_tpl=$( _cleanup "${pages_tpl}" ) - - # Write pages_tpl to disk - # _msg std "Writing ${config[site_root]}/${pages_title_lower%.*}.html to disk." - echo "${pages_tpl}" > ${config[site_root]}/${pages_title_lower%.*}.html - - # Insert the blog to the front page is blog_in_index is true and the file in the array is index.file_ext - # and if index.tmp.html exist and is not empty - if [[ ${pages_in_array} == "index.${file_ext}" && ${config[site_blog]} == "true" && -s "${config[project_root]}/blog/index.tmp.html" ]]; then - if (${debug}) _msg sub "${0:t}_msg_24" " ${pages_in_array}" - if (${debug}) _msg sub "${0:t}_msg_25" " ${config[site_blog]}" - if (${debug}) _msg sub "${0:t}_msg_26" - if (${debug}) ls -l ${config[project_root]}/blog/index.tmp.html - _add_blog_list_to_index - fi - - done - - export new_updated_pages=true - - else - # Insert the blog to the front page is blog_in_index is true and the file in the array is index.file_ext - # and if index.tmp.html exist and is not empty - if [[ ${config[site_blog]} == "true" && -s "${config[project_root]}/blog/index.tmp.html" ]]; then - _msg std "${0:t}_msg_27" - if (${debug}) _msg sub "${0:t}_msg_28" " ${pages_in_array}" - if (${debug}) _msg sub "${0:t}_msg_29" " ${config[site_blog]}" - if (${debug}) _msg sub "${0:t}_msg_30" - if (${debug}) ls -l ${config[project_root]}/blog/index.tmp.html - _add_blog_list_to_index - fi - - _msg sub "${0:t}_msg_31" - export new_updated_pages=false - - fi - -} - -function _blogs() { - # This function either generates blog files or exports metadata based on the argument - - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - _msg main "${0:t}_msg_3" - - # Running function _list_blogs - if (${debug}) _msg debug "${0:t}_msg_1" - _list_blogs - - if [[ ${no_blogs_found} == "true" ]]; then - _msg sub "${0:t}_msg_2" - return - fi - - # Running function _blog_cache - if (${debug}) _msg debug "${0:t}_msg_4" - _blog_cache - - if (( ${#make_blog_array[@]} > 0 )); then - - # Declare arrays to hold blog content and metadata - typeset -ga BLOG_META_STR_ARRAY - typeset -A blog_contents - typeset -A blog_metadata - - # Array to store PIDs of background jobs - local pids=() - # Counter for active jobs - local active_jobs=0 - # Maximum number of parallel jobs (configurable, default to number of CPU cores) - local max_jobs=${config[parallel_jobs]:-$(nproc)} - - # Load template once before processing - if [[ -f ${config[project_root]}/themes/${config[site_theme]}/blogs.tpl ]]; then - local blog_tpl=$(<"${config[project_root]}/themes/${config[site_theme]}/blogs.tpl") - else - _msg info "${0:t}_msg_5" - exit - fi - - # Create a FIFO for inter-process communication - local fifo=$(mktemp -u) - mkfifo "${fifo}" - - # Function to process a single blog file - _process_blog() { - local blog="$1" - local debug="$2" - local blog_tpl="$3" - - # Process in a subshell to avoid variable conflicts - ( - # Process blog in memory - local content="$(<"${blog}")" - local sdate btitle ingress body blog_index blog_dir blog_url - local date_found=false - local title_found=false - - # Process content line by line - while IFS= read -r line; do - [[ "${line}" == "DATE "* ]] && { date_found=true; sdate=(${line#DATE }); } - [[ "${line}" == "BLOG_TITLE "* ]] && { title_found=true; btitle="${line#BLOG_TITLE }"; } - [[ "${date_found}" == true && "${title_found}" == true ]] && break - done <<< "${content}" - - # Skip if required metadata is missing - [[ "${date_found}" != true || "${title_found}" != true ]] && return 1 - - # Extract blog content - ingress=$(echo "${content}" | sed "s/'/\\\'/g" | xargs | - grep -Po "#INGRESS_START\K(.*?)#INGRESS_STOP" | - sed "s|\ \#INGRESS_STOP||; s|^\ ||") - - body=$(echo "${content}" | sed "s/'/\\\'/g" | xargs | - grep -Po "#BODY_START\K(.*?)#BODY_STOP" | - sed "s|\ \#BODY_STOP||; s|^\ ||") - - # Process blog metadata - sdate=($(echo ${sdate} | sed 's|-| |g')) - blog_index=$(echo "${btitle:l}" | sed 's/ /_/g; s/[,.:()]//g') - blog_dir="/blog/${sdate[2]}/${sdate[3]:l}/${sdate[4]}" - blog_url="${blog_dir}/${blog_index}.html" - - # Generate blog content with template - local blog_content=$(echo "${blog_tpl}" | \ - perl -pe " - s|BLOGTITLE|${btitle}|g; - s|BLOGURL|${blog_url}|g; - s|\QINGRESS\E|${ingress}|g; - s|\QBODY\E|${body}|g") - - # Apply template variables - blog_content="${blog_content//CALNDAY/${sdate[4]}}" - blog_content="${blog_content//CALYEAR/${sdate[2]}}" - blog_content="${blog_content//CALMONTH/${sdate[3]}}" - blog_content="${blog_content//CALADAY/${sdate[1]}}" - - # Process content with engine and plugins - blog_content=$(_run_engine "${blog_content}") - [[ "${blog_content}" == *"#link"* ]] && blog_content=$(_link "${blog_content}") - [[ "${blog_content}" == *"#showimg"* ]] && blog_content=$(_image "${blog_content}") - [[ "${blog_content}" == *"#linkimg"* ]] && blog_content=$(_linkimg "${blog_content}") - [[ "${blog_content}" == *"#ytvideo"* ]] && blog_content=$(_youtube "${blog_content}") - - # Apply site-wide variables - blog_content=$(echo "${blog_content}" | \ - perl -pe "s|#tagline|${config[site_tagline]}|gs; - s|#sitename|${config[site_name]}|gs; - s|#pagetitle|${page_title}|gs") - - # Final processing - blog_content=$(_last_updated "${blog_content}") - blog_content=$(_cleanup "${blog_content}") - - # Output metadata and content through FIFO - echo "${blog}:" - echo " dir: ${blog_dir}" - echo " url: ${blog_url}" - echo " title: ${btitle}" - echo " content: |" - echo " ${blog_content//$'\n'/$'\n '}" - echo "---" - ) > "${fifo}.${blog//\//_}" & - - return $? - } - - # Start a background process to read from FIFO - local reader_pid - ( - while IFS= read -r line; do - if [[ $line == *":" ]]; then - current_blog="${line%:}" - elif [[ $line == " dir: "* ]]; then - blog_metadata["${current_blog}_dir"]="${line# dir: }" - elif [[ $line == " url: "* ]]; then - blog_metadata["${current_blog}_url"]="${line# url: }" - elif [[ $line == " title: "* ]]; then - blog_metadata["${current_blog}_title"]="${line# title: }" - elif [[ $line == " content: |" ]]; then - blog_content="" - while IFS= read -r content_line; do - [[ $content_line == " "* ]] || break - blog_content+="${content_line# }\n" - done - blog_contents["${current_blog}"]="${blog_content%\n}" - fi - done < <(cat "${fifo}".* 2>/dev/null) - ) & - reader_pid=$! - - # Export functions and variables needed in subshells - export -f _run_engine _link _image _linkimg _youtube _last_updated _cleanup - export config - - # Process blogs in parallel - for blog in "${make_blog_array[@]}"; do - # Wait for a slot if we've reached max jobs - while (( active_jobs >= max_jobs )); do - # Check for completed jobs - local new_pids=() - local completed=0 - for pid in "${pids[@]}"; do - if kill -0 "$pid" 2>/dev/null; then - new_pids+=("$pid") - else - ((completed++)) - fi - done - pids=("${new_pids[@]}") - ((active_jobs -= completed)) - - # If still at max, wait a bit - (( active_jobs >= max_jobs )) && sleep 0.1 - done - - # Start a new job - if (${debug}) _msg debug "Processing blog: ${blog}" - _process_blog "${blog}" "${debug}" "${blog_tpl}" & - pids+=($!) - ((active_jobs++)) - done - - # Wait for all background jobs to complete - wait "${pids[@]}" 2>/dev/null - - # Signal the reader to finish - wait $reader_pid 2>/dev/null - - # Write all blogs to disk in a single pass - for blog in "${!blog_contents[@]}"; do - local dir="${blog_metadata[${blog}_dir]}" - local url="${blog_metadata[${blog}_url]}" - local title="${blog_metadata[${blog}_title]}" - local content="${blog_contents[$blog]}" - - # Skip if required fields are missing - if [[ -z "$dir" || -z "$url" || -z "$content" ]]; then - _msg warning "Skipping blog post due to missing metadata: ${blog}" - continue - fi - - # Construct the full output path safely - local output_path - output_path=$(_safe_path "${config[site_root]}" "${url#/}") || { - _msg error "Invalid output path for blog: $url" - continue - } - - # Create output directory if it doesn't exist - local output_dir - output_dir=$(dirname -- "$output_path") - if ! mkdir -p -- "$output_dir"; then - _msg error "Failed to create directory: $output_dir" - continue - fi - - # Write the blog content safely - if ! _safe_write "$content" "$output_path"; then - _msg error "Failed to write blog post: $output_path" - continue - fi - - # Add to metadata array for index generation - BLOG_META_STR_ARRAY+=("SDATA:${dir}||BTITLE:${title}||INGRESS:${content}||URL:${url}") - - if (${debug}); then - _msg debug "Successfully wrote blog post: $output_path" - fi - done - - # Clean up FIFO files - rm -f "${fifo}" "${fifo}".* 2>/dev/null - # Process each blog in parallel - # Now BLOG_META_STR_ARRAY contains the metadata string for each blog post - export BLOG_META_STR_ARRAY - if (${debug}) _msg debug "${0:t}_msg_24" - export new_updated_blogs=true - - else - _msg sub "${0:t}_msg_25" - export new_updated_blogs=false - fi - - if [[ ${new_updated_blogs} == "true" ]]; then - if (${debug}) _msg sub "${0:t}_msg_26" - _blog_idx_for_index - if (${debug}) _msg sub "${0:t}_msg_27" - _blog_index - fi - -} - -function _blog_idx_for_index() { - # This function generates the file blog/index.tmp.html - - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - _msg sub "${0:t}_msg_1" " ${config[project_root]}/blog/index.tmp.html" - - if (${debug}) _msg debug "${0:t}_msg_2" - - local blog_list_tpl=$(<${config[project_root]}/themes/${config[site_theme]}/blog_list.tpl) - local blog_list_content="" - - # Truncate file before writing new one - : >| "${config[project_root]}/blog/index.tmp.html" - - # if (${debug}) _msg debug "${0:t}_msg_3" " ${BLOG_META_STR_ARRAY[@]}" - - for meta_str in ${BLOG_META_STR_ARRAY[@]} - do - if (${debug}) _msg debug "${0:t}_msg_4" - if (${debug}) _msg debug "${0:t}_msg_5" " ${meta_str}" - - # Split meta_str into individual metadata components - local -a meta_array=("${(@s/||/)meta_str}") - - # Initialize variables to store each component - local sdate btitle ingress url - - # Iterate over each component and extract information - if (${debug}) _msg debug "${0:t}_msg_6" - for component in "${meta_array[@]}" - do - case "${component}" in - SDATE:*) sdate=${component#SDATE: } ;; - BTITLE:*) btitle=${component#BTITLE: } ;; - INGRESS:*) ingress=${component#INGRESS: } ;; - URL:*) url=${component#URL: } ;; - esac - - done - - local adate=( $( echo ${sdate} ) ) - local caladay="${adate[1]}" - local calyear="${adate[2]}" - local calmonth="${adate[3]}" - local calnday="${adate[4]}" - - local bdate="${adate[1]} - ${adate[4]}/${adate[3]}/${adate[2]}" - blog_list_content+=$( - echo "${blog_list_tpl}" | \ - perl -pe "\ - s|BLOGURL|${config[site_url]}${url}|g; \ - s|BLOGTITLE|${btitle}|g; \ - s|INGRESS|${ingress}|g; \ - s|BLOGDATE|${bdate}|g; \ - s|CALADAY|${caladay}|g; \ - s|CALNDAY|${calnday}|g; \ - s|CALMONTH|${calmonth}|g; \ - s|CALYEAR|${calyear}|g \ - ") - - unset sdate btitle ingress url adate caladay calyear calmonth calnday - - done - if (${debug}) _msg debug "${0:t}_msg_7" " ${engine} " "${0:t}_msg_7.1" - # Catch any QStags or Markdown in the Ingress - blog_list_content=$( _run_engine ${blog_list_content} ) - if (${debug}) _msg debug "${0:t}_msg_8" " ${config[project_root]}/blog/index.tmp.html" - #if (${debug}) _msg debug "${0:t}_msg_9" " ${blog_list_content}" - echo ${blog_list_content} > ${config[project_root]}/blog/index.tmp.html - _update_blog_cache - -} - -function _blog_index() { - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - # Check if we need to update the blog index - if [[ ${new_updated_blogs} == "true" ]] || _is_blog_cache_stale; then - if (${debug}) _msg debug "Generating new blog index" - - # Get the template - local blog_index_tpl=$(<${config[project_root]}/themes/${config[site_theme]}/blog_index.tpl) - - # Get the blog list content - local blog_index_list - if [[ ${new_updated_blogs} == "true" ]]; then - # If we have new/updated blogs, use the fresh content - blog_index_list=$(<${config[project_root]}/blog/index.tmp.html) - else - # Otherwise try to load from cache - blog_index_list=$(_load_blog_cache) || { - # If cache load fails, use the fresh content - blog_index_list=$(<${config[project_root]}/blog/index.tmp.html) - } - fi - - # Generate the final content - local blog_index_content=$(echo "${blog_index_tpl}" | \ - perl -pe "s|#sitename|${config[site_name]}|gs; s|#tagline|${config[site_tagline]}|gs") - blog_index_content=$(awk -v new_body="$blog_index_list" '{sub(/BODY/, new_body)} 1' <(echo "${blog_index_content}")) - - # Create output directory if it doesn't exist - mkdir -p "${config[site_root]}/blog" - - # Write the index file - echo "$blog_index_content" > "${config[site_root]}/blog/index.html" - _f_last_updated "${config[site_root]}/blog/index.html" - - # Update the cache with the new content - _update_blog_cache - - if (${debug}); then - _msg debug "Generated new blog index at ${config[site_root]}/blog/index.html" - _msg debug "Blog index size: ${#blog_index_content} bytes" - fi - else - # Use cached content - if (${debug}) _msg debug "Using cached blog index" - local cached_content=$(_load_blog_cache) - mkdir -p "${config[site_root]}/blog" - echo "$cached_content" > "${config[site_root]}/blog/index.html" - fi -} - -function _add_blog_list_to_index() { - - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - # Let's find the file 'index.qst' and add the blog if blog_in_index is true - if (${debug}) _msg debug "${0:t}_msg_1" - local blog_index_list=$(<${config[project_root]}/blog/index.tmp.html) - local site_index_file=$(<${config[site_root]}/index.html) - echo "${site_index_file}" | awk -v new_body="${blog_index_list}" '{sub(/BLOGINDEX/, new_body)} 1' > "${config[site_root]}/index.html" - -} - -function _sitemap() { - - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - # Check if sitemap is set to true and if there are updated Blogs, Pages, or if cache is stale - if ([[ ${config[site_sitemap]} == "true" ]] && - ([[ ${new_updated_blogs} == "true" ]] || - [[ ${new_updated_pages} == "true" ]] || - _is_blog_cache_stale)) || - [[ ${sitemap_force} == "true" ]]; then - - setopt extendedglob - - _msg main "${0:t}_msg_1" - - local sm_file="sitemap.xml" - local b_file="sitemap-blogs.xml" - local p_file="sitemap-pages.xml" - local sitemap_file="${config[site_root]}/${sm_file}" - local sitemap_blog="${config[site_root]}/${b_file}" - local sitemap_page="${config[site_root]}/${p_file}" - - # Find all HTML files and store them in an array - builtin cd ${config[site_root]} - local -a html_files=(**/[a-z]*.html(.)) - local -a blog_files=() - local -a page_files=() - for file in "${html_files[@]}"; do - if [[ $file == *blog* ]]; then - blog_files+=("$file") - else - page_files+=("$file") - fi - done - - # Start of the XML file for BLOGS - echo '' > ${sitemap_blog} - echo "" >> ${sitemap_blog} - echo "" >> ${sitemap_blog} - echo '> ${sitemap_blog} - echo ' xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"' >> ${sitemap_blog} - echo ' xmlns:xhtml="http://www.w3.org/1999/xhtml"' >> ${sitemap_blog} - echo ' xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"' >> ${sitemap_blog} - echo '>' >> ${sitemap_blog} - - # Add each URL to the sitemap - for file in "${blog_files[@]}" - do - # Remove www_root from the path and prepend site_url - local url="${config[site_url]}/${file}" - local lastmod=$(stat -c %y "${file}" 2>/dev/null | cut -d' ' -f1,2 | sed 's/ /T/' | sed 's/\..*$//') - - echo " " >> ${sitemap_blog} - echo " ${url}" >> ${sitemap_blog} - echo " " >> ${sitemap_blog} - echo " " >> ${sitemap_blog} - echo " " >> ${sitemap_blog} - echo " " >> ${sitemap_blog} - done - - # End of the XML file - echo '' >> "${sitemap_blog}" - _msg std " - ${b_file}" - - # Start of the XML file for PAGES - echo '' > ${sitemap_page} - echo "" >> ${sitemap_page} - echo "" >> ${sitemap_page} - echo '> ${sitemap_page} - echo ' xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"' >> ${sitemap_page} - echo ' xmlns:xhtml="http://www.w3.org/1999/xhtml"' >> ${sitemap_page} - echo ' xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"' >> ${sitemap_page} - echo '>' >> ${sitemap_page} - - # Add each URL to the sitemap - for file in "${page_files[@]}" - do - # Remove www_root from the path and prepend site_url - local url="${config[site_url]}/${file}" - local lastmod=$(stat -c %y "${file}" 2>/dev/null | cut -d' ' -f1,2 | sed 's/ /T/' | sed 's/\..*$//') - - echo " " >> ${sitemap_page} - echo " ${url}" >> ${sitemap_page} - echo " " >> ${sitemap_page} - echo " " >> ${sitemap_page} - echo " " >> ${sitemap_page} - echo " " >> ${sitemap_page} - done - - # End of the XML file - echo '' >> "${sitemap_page}" - _msg std " - ${p_file}" - - # Update the blog cache after generating sitemap - _update_blog_cache - - if (${debug}); then _msg debug "${0:t}_msg_2" " ${sitemap_file}"; fi - - # Start of the XML file for the main sitemap - echo '' > "${sitemap_file}" - echo "" >> "${sitemap_file}" - - # Add sitemap-blogs.xml to the sitemap - echo " " >> "${sitemap_file}" - echo " ${config[site_url]}/${b_file}" >> "${sitemap_file}" - local lastmod_b=$(stat -c %y "${b_file}" 2>/dev/null | cut -d' ' -f1,2 | sed 's/ /T/' | sed 's/\..*$//') - echo " ${lastmod_b}" >> "${sitemap_file}" - echo " " >> "${sitemap_file}" - - # Add sitemap-pages.xml to the sitemap - echo " " >> "${sitemap_file}" - echo " ${config[site_url]}/${p_file}" >> "${sitemap_file}" - local lastmod_p=$(stat -c %y "${p_file}" 2>/dev/null | cut -d' ' -f1,2 | sed 's/ /T/' | sed 's/\..*$//') - echo " ${lastmod_p}" >> "${sitemap_file}" - echo " " >> "${sitemap_file}" - - # End of the XML file - echo "" >> "${sitemap_file}" - _msg std " - ${sm_file}" - - builtin cd ${config[project_root]} - - fi - -} - -function _link() { - # This converts #link tags to actual clickable links in a provided string - - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - local content="${1}" - local modified_content="" - - # Process the content line by line - echo "${content}" | while IFS= read -r line; do - if [[ ${line} == *"#link"* ]]; then - if (${debug}) _msg debug "${0:t}_msg_1" " ${line}" - - # Extract the URL and the link text - local url_full=$(echo "${line}" | awk -F'#link ' '{print $2}' | awk -F'¤' '{print $1 "¤" $2}') - local url_dest=$(echo "${url_full}" | awk -F'¤' '{print $1}') - local url_txt=$(echo "${url_full}" | awk -F'¤' '{print $2}') - - if (${debug}) _msg debug "${0:t}_msg_2" " ${url_dest}" - if (${debug}) _msg debug "${0:t}_msg_3" " ${url_txt}" - - # Form the replacement HTML link - local modified_link="${url_txt}" - if [[ ${url_dest} =~ ^https?:// ]]; then - # Add external link icon for external URLs - modified_link+="\"External" - fi - modified_link+="" - line=${line//"#link ${url_full}"/${modified_link}} - fi - modified_content+="${line}\n" - done - - # Return the modified content - echo -e "${modified_content}" - -} - -function _image() { - # This replaces #showimg tags with actual HTML img tags in a provided string - - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - local content="${1}" - local modified_content="" - - # Process the content line by line - echo "${content}" | while IFS= read -r line; do - if [[ ${line} == *"#showimg"* ]]; then - if (${debug}) _msg debug "${0:t}_msg_1" " ${line}" - - # Extract image link and alt text - local img_link=$(echo "${line}" | awk -F'#showimg ' '{print $2}') - local image=$(echo "${img_link}" | awk -F'¤' '{print $1}') - local img_alt=$(echo "${img_link}" | awk -F'¤' '{print $2}') - - # Determine the source of the image - local real_image="" - if [[ ${image} =~ ^https?:// ]]; then - real_image=${image} - elif [[ ${image} =~ ^\/ ]]; then - real_image=${image} - else - real_image="/images/${image}" - fi - - # Form the replacement HTML image tag - local img_tag="\"${img_alt}\"" - line=${line//"#showimg ${img_link}"/${img_tag}} - fi - modified_content+="${line}\n" - done - - # Return the modified content - echo -e "${modified_content}" - -} - -function _linkimg() { - # This function replaces #linkimg tags with tags around tags - - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - local content="${1}" - local modified_content="" - - # Process the content line by line - echo "${content}" | while IFS= read -r line; do - if [[ ${line} == *"#linkimg"* ]]; then - if (${debug}) _msg debug "${0:t}_msg_1" " ${line}" - - # Extract link, image, and alt text - local img_link=$(echo "${line}" | awk -F'#linkimg ' '{print $2}') - local img_url=$(echo "${img_link}" | awk -F'¤' '{print $1}') - local img_alt=$(echo "${img_link}" | awk -F'¤' '{print $2}') - - # Determine the source of the image - local real_image="" - if [[ ${img_url} =~ ^https?:// ]]; then - real_image=${img_url} - elif [[ ${img_url} =~ ^\/ ]]; then - real_image=${img_url} - else - real_image="/images/${img_url}" - fi - - # Form the replacement HTML link and image tag - local img_tag="\"${img_alt}\"" - line=${line//"#linkimg ${img_link}"/${img_tag}} - fi - modified_content+="${line}\n" - done - - # Return the modified content - echo -e "${modified_content}" -} - -function _youtube() { - # This embeds a YouTube video in a provided string - - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - local content="${1}" - local modified_content="" - - # Process the content line by line - echo "${content}" | while IFS= read -r line; do - if [[ ${line} == *"#ytvideo"* ]]; then - if (${debug}) _msg debug "${0:t}_msg_1" " ${line}" - - # Extract YouTube video ID - local yt_id=$(echo "${line}" | awk -F'#ytvideo ' '{print $2}') - - # Form the replacement YouTube iframe embed - local yt_iframe="" - line=${line//"#ytvideo ${yt_id}"/${yt_iframe}} - fi - modified_content+="${line}\n" - done - - # Return the modified content - echo -e "${modified_content}" - -} - -function _cleanup() { - # This removes tags used in the templates that may be left over for some reason - - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - local content="${1}" - - if (${debug}) _msg debug "${0:t}_msg_1" - - # Perform the cleanup - # -e "s|BLOGINDEX\ ||g" - local cleaned_content=$(echo "${content}" | sed \ - -e "s|¤||g" \ - -e "s|#showimg\ ||g" \ - -e "s|#ytvideo\ ||g" \ - -e "s|#link\ ||g" \ - -e "s|#linkimg\ ||g" \ - ) - - # Return the cleaned content - echo "${cleaned_content}" - -} - -function _p_qstags() { - - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - local content="${1}" - - if ${debug}; then - _msg debug "${0:t}_msg_1" - fi - - # Use perl to convert QStags to HTML - perl -0777 -pe ' - BEGIN { - @qstags = ( - "#BR", "
\n", - "#BD", "", "#EBD", "", - "#I", "", "#EI", "\n", - "#P", "

", "#EP", "

\n", - "#Q", "
", "#EQ", "
\n", - "#C", "", "#EC", "\n", - "#H1", "

", "#EH1", "

\n", - "#H2", "

", "#EH2", "

\n", - "#H3", "

", "#EH3", "

\n", - "#H4", "

", "#EH4", "

\n", - "#H5", "
", "#EH5", "
\n", - "#H6", "
", "#EH6", "
\n", - "#STRONG", "", "#ESTRONG", "\n", - "#EM", "", "#SEM", "\n", - "#DV", "
", "#EDV", "
\n", - "#SPN", "", "#ESPN", "\n", - "#UL", "
    ", "#EUL", "
\n", - "#OL", "
    ", "#EOL", "
\n", - "#LI", "
  • ", "#ELI", "
  • \n", - "#UD", "", "#EUD", "\n", - "#TBL", "", "#ETBL", "
    \n", - "#TR", "", "#ETR", "\n", - "#TD", "", "#ETD", "\n", - "#TH", "", "#ETH", "\n", - "#ART", "
    ", "#EART", "
    \n", - "#SEC", "
    ", "#ESEC", "
    \n", - "#ASIDE", "\n", - "#NAV", "\n", - "#BTN", "\n", - "#SEL", "\n", - "#OPT", "\n", - "#LT", "<", "#GT", ">", "#NUM", "#" - ); - } - - for (my $i = 0; $i < $#qstags; $i += 2) { - my $qstag = $qstags[$i]; - my $html = $qstags[$i + 1]; - s/\Q$qstag\E/$html/g; - } - ' <<< "$content" - -} - -############################################################################### -# MARKUP CONVERSION FUNCTIONS -# These functions handle conversion between QSTags and Markdown formats -############################################################################### - -# _convert_markup - Main function for converting between QSTags and Markdown -# -# This function provides a unified interface for converting between QSTags (used internally -# by qsgen2) and Markdown (a more standard markup format). It supports both single file -# and batch processing modes. -# -# Usage: -# _convert_markup [--to-markdown|--to-qstags] [--all] [input_file] [output_file] -# -# Options: -# --to-markdown Convert from QSTags to Markdown format -# --to-qstags Convert from Markdown to QSTags format -# --all Process all .qst and .blog files in the project -# -# If no files are provided, reads from stdin and writes to stdout. -# If no mode is specified, auto-detects based on file extension or content. -# -# Examples: -# # Convert a single file -# _convert_markup --to-markdown page.qst page.md -# -# # Convert all files in batch mode -# _convert_markup --to-markdown --all - local mode="" - local process_all=false - local input_file="-" # Default to stdin - local output_file="-" # Default to stdout - - # Parse arguments - while [[ $# -gt 0 ]]; do - case "$1" in - --to-markdown) - mode="to_markdown" - shift - ;; - --to-qstags) - mode="to_qstags" - shift - ;; - --all) - process_all=true - shift - ;; - *) - if [[ -z "$input_file" || "$input_file" == "-" ]]; then - input_file="$1" - else - output_file="$1" - fi - shift - ;; - esac - done - - # If --all is specified, process all .qst and .blog files - if [[ "$process_all" == true ]]; then - if [[ -z "$mode" ]]; then - _msg error "Please specify --to-markdown or --to-qstags with --all" - return 1 - fi - - local target_ext="md" # Always use .md for markdown output - if [[ "$mode" == "to_qstags" ]]; then - # For QSTags output, we need to know if it's a page or blog post - # This will be handled in the file processing loops - : - fi - - # Process pages (.qst files) - local page_count=0 - local blog_count=0 - - # Process pages - for page in "${config[project_root]}"/*.qst; do - [[ -f "$page" ]] || continue - local output_file - if [[ "$mode" == "to_markdown" ]]; then - output_file="${page%.qst}.md" - else - output_file="${page%.qst}.qst" # Keep original extension - fi - _msg info "Converting ${page##*/} to ${output_file##*/}" - _convert_single_file "$page" "$output_file" "$mode" - ((page_count++)) - done - - # Process blog posts - if [[ -d "${config[project_root]}/blog" ]]; then - for blog in "${config[project_root]}/blog/"*.blog; do - [[ -f "$blog" ]] || continue - local output_file - if [[ "$mode" == "to_markdown" ]]; then - output_file="${blog%.blog}.md" - else - output_file="${blog%.blog}.blog" # Keep original extension - fi - _msg info "Converting ${blog##*/} to ${output_file##*/}" - _convert_single_file "$blog" "$output_file" "$mode" - ((blog_count++)) - done - fi - - _msg success "Converted $page_count pages and $blog_count blog posts" - return 0 - fi - - # If no mode specified, try to auto-detect - if [[ -z "$mode" ]]; then - if [[ "$input_file" != "-" ]] && [[ "$input_file" == *.md || "$input_file" == *.markdown ]]; then - mode="to_qstags" - else - mode="to_markdown" - fi - fi - - # Process a single file - _convert_single_file "$input_file" "$output_file" "$mode" -} - -function _convert_single_file() { - local input_file="$1" - local output_file="$2" - local mode="$3" - - # Read input - local content - if [[ "$input_file" == "-" ]]; then - content=$(cat -) - else - [[ -f "$input_file" ]] || { _msg error "Input file not found: $input_file"; return 1; } - content=$(<"$input_file") - fi - - # Conversion logic - # - # The conversion uses sed with extended regular expressions to perform pattern - # matching and substitution. Each pattern handles a specific QSTag or Markdown - # construct, converting it to the target format. - # - # Note: The order of replacements is significant as some patterns may be - # prefixes of others. - case "$mode" in - to_markdown) - # Convert QSTags to Markdown - # - # Pattern explanations: - # s/#BR/\n/g - Line breaks - # s/#BD(.*?)#EBD/**\1**/g - Bold text - # s/#I(.*?)#EI/*\1*/g - Italic text - # s/#P\s*/\n\n/g; s/#EP//g - Paragraphs - # s/#Q\s*/> /g; s/#EQ//g - Blockquotes - # s/#C(.*?)#EC/`\1`/g - Inline code - # s/#H1\s*/# /g; s/#EH1//g - Headers (H1-H6) - # ... and so on for other QSTags - content=$(echo "$content" | sed -E '\ - s/#BR/\n/g;\ - s/#BD(.*?)#EBD/**\1**/g;\ - s/#I(.*?)#EI/*\1*/g;\ - s/#P\s*/\n\n/g; s/#EP//g;\ - s/#Q\s*/> /g; s/#EQ//g;\ - s/#C(.*?)#EC/`\1`/g;\ - s/#H1\s*/# /g; s/#EH1//g;\ - s/#H2\s*/## /g; s/#EH2//g;\ - s/#H3\s*/### /g; s/#EH3//g;\ - s/#H4\s*/#### /g; s/#EH4//g;\ - s/#H5\s*/##### /g; s/#EH5//g;\ - s/#H6\s*/###### /g; s/#EH6//g;\ - s/#STRONG(.*?)#ESTRONG/**\1**/g;\ - s/#EM(.*?)#SEM/*\1*/g;\ - s/#UL\s*/\n/g; s/#EUL//g;\ - s/#OL\s*/\n/g; s/#EOL//g;\ - s/#LI\s*/- /g; s/#ELI//g;\ - s/#TBL\s*/\n/g; s/#ETBL//g;\ - s/#TR//g; s/#ETR//g;\ - s/#TD/| /g; s/#ETD/ |/g;\ - s/#TH/| **/g; s/#ETH/** |/g;\ - s/#LT//g; s/#NUM/#/g\ - ') - ;; - - to_qstags) - # Convert Markdown to QSTags - # - # This is the inverse of the to_markdown conversion, translating - # Markdown syntax back to QSTags. The patterns are designed to handle - # the most common Markdown constructs while being reasonably robust - # against variations in whitespace and formatting. - # - # Note: Some Markdown features may not have direct QSTag equivalents - # and will be preserved as plain text. - content=$(echo "$content" | sed -E '\ - s/\*\*(.*?)\*\*/#BD\1#EBD/g;\ - s/\*(.*?)\*/#I\1#EI/g;\ - s/^# (.*)$/#H1 \1#EH1/g;\ - s/^## (.*)$/#H2 \1#EH2/g;\ - s/^### (.*)$/#H3 \1#EH3/g;\ - s/^#### (.*)$/#H4 \1#EH4/g;\ - s/^##### (.*)$/#H5 \1#EH5/g;\ - s/^###### (.*)$/#H6 \1#EH6/g;\ - s/^> (.*)$/#Q \1#EQ/g;\ - s/`([^`]+)`/#C\1#EC/g;\ - s/^\s*[-*+]\s+(.*)$/#LI \1#ELI/g;\ - s/\n\s*\n/#P\n/g;\ - s//#GT/g\ - ') - ;; - esac - - # Write output - if [[ "$output_file" == "-" ]]; then - echo "$content" - else - echo "$content" > "$output_file" - fi -} - -function _qstags() { - # This function uses the regex module from Zsh to parse the QStags - - if [[ ${globaldebug} == "true" ]]; then - local debug=true - else - local debug=false - fi - - local content="${1}" - - if ${debug}; then - _msg debug "${0:t}_msg_1" - fi - - # Load regex module - # zmodload zsh/regex - - # Define tag replacements as an associative array - typeset -A qstags=( - "#BR" "
    \n" - "#BD" "" "#EBD" "" - "#I" "" "#EI" "\n" - "#P" "

    " "#EP" "

    \n" - "#Q" "
    " "#EQ" "
    \n" - "#C" "" "#EC" "\n" - "#H1" "

    " "#EH1" "

    \n" - "#H2" "

    " "#EH2" "

    \n" - "#H3" "

    " "#EH3" "

    \n" - "#H4" "

    " "#EH4" "

    \n" - "#H5" "
    " "#EH5" "
    \n" - "#H6" "
    " "#EH6" "
    \n" - "#STRONG" "" "#ESTRONG" "\n" - "#EM" "" "#SEM" "\n" - "#DV" "
    " "#EDV" "
    \n" - "#SPN" "" "#ESPN" "\n" - "#UL" "
      " "#EUL" "
    \n" - "#OL" "
      " "#EOL" "
    \n" - "#LI" "
  • " "#ELI" "
  • \n" - "#UD" "" "#EUD" "\n" - "#TBL" "" "#ETBL" "
    \n" - "#TR" "" "#ETR" "\n" - "#TD" "" "#ETD" "\n" - "#TH" "" "#ETH" "\n" - "#ART" "
    " "#EART" "
    \n" - "#SEC" "
    " "#ESEC" "
    \n" - "#ASIDE" "\n" - "#NAV" "\n" - "#BTN" "\n" - "#SEL" "\n" - "#OPT" "\n" - "#LT" "<" "#GT" ">" "#NUM" "#" - ) - - #for qstag html (${(kv)qstags}) - # do - # # Escape tag for regex use - # local escapedTag=$(printf '%s' "$qstag" | sed 's/[].\[^$*]/\\&/g') - # if [[ "$content" =~ "$escapedTag" ]]; then - # content=${content//($qstag)/$html} - # fi - #done - for qstag html (${(kv)qstags}); do - # Direct replacement without regex check - content=${content//${qstag}/${html}} - done - - echo "${content}" - -} - - -case ${1} in - force) - _msg sub "_qsgen2_msg_2" - : >| "$blog_cache_file" # Truncate the blog cache before doing update - : >| "$pages_cache_file" # Truncate the page cache before doing update - ;; - sitemap) - _msg sub "Updating sitemaps" - export sitemap_force=true - _sitemap - exit - ;; - *) - # Nothing - ;; -esac - -_blogs -_pages -_sitemap