From 91b0bbd1124930e117483843d28018f233d3995e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stig-=C3=98rjan=20Smelror?= Date: Sun, 18 May 2025 19:01:39 +0200 Subject: [PATCH] feat(i18n): add Norwegian (nb_NO) translation and clean up - Add complete Norwegian (nb_NO) language file - Update .gitignore to exclude temporary and backup files - Remove temporary and backup files from language directory - Clean up scripts directory and add to .gitignore - Update language file format to use key-value pairs --- .gitignore | 58 ++ HOWTO.md | 220 +++++ include/qsgen2/lang/en_UK | 334 ++++--- include/qsgen2/lang/en_US | 334 ++++--- include/qsgen2/lang/es_ES | 324 ++++--- include/qsgen2/lang/fr_FR | 326 ++++--- include/qsgen2/lang/nb_NO | 332 ++++--- qsgen2 | 1363 +++++++++++++++++++++------ config.example => site.conf.example | 0 tools/extract_messages.sh | 144 +++ tools/migrate_messages.sh | 63 ++ tools/migrate_messages_to_system.sh | 68 ++ 12 files changed, 2674 insertions(+), 892 deletions(-) create mode 100644 .gitignore create mode 100644 HOWTO.md rename config.example => site.conf.example (100%) create mode 100755 tools/extract_messages.sh create mode 100755 tools/migrate_messages.sh create mode 100755 tools/migrate_messages_to_system.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5166ce4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,58 @@ +# Temporary files +*.tmp +*.bak +*.backup +*.swp +*.swo +*~ +*.new +*.en +.DS_Store +.idea/ +.vscode/ + +# Language directory temporary files +include/qsgen2/lang/*.backup +include/qsgen2/lang/*.bak +include/qsgen2/lang/*.new +include/qsgen2/lang/*.txt +include/qsgen2/lang/*.en + +# Scripts directory (temporary/conversion scripts) +/scripts/ + +# Build output +/build/ +/dist/ +*.o + +# Python cache +__pycache__/ +*.py[cod] +*$py.class + +# Node modules +node_modules/ + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Local development files +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/HOWTO.md b/HOWTO.md new file mode 100644 index 0000000..99b18ff --- /dev/null +++ b/HOWTO.md @@ -0,0 +1,220 @@ +# 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/include/qsgen2/lang/en_UK b/include/qsgen2/lang/en_UK index c1cdeef..c30f7f3 100644 --- a/include/qsgen2/lang/en_UK +++ b/include/qsgen2/lang/en_UK @@ -1,117 +1,217 @@ -qsgenlang=( -_qsgen2_msg_2 "- Forced Update: Generating Everything" -_qsgen2_msg_3 "* %SCRIPT_NAME% cannot parse this site. Exiting. *" -_qsgen2_msg_4 "Please install Pandoc." -_qsgen2_msg_5 "No valid generator found. Are you sure you've selected the correct generator in 'config'?" -_qsgen2_msg_6 "Using the" -_qsgen2_msg_6.1 "-engine for files:" -_qsgen2_msg_7 "- Created by kekePower - 2018-" -_qsgen2_msg_8 "- See" -_qsgen2_msg_8.1 "for more information." -_qsgen2_msg_9 "Contents of the Config file:" -_list_pages_msg_1 "_list_pages: No Pages found with extension" -_list_pages_msg_2 "_list_pages: Adding file to array:" -_list_blogs_msg_1 "_list_blogs: No blog files found." -_list_blogs_msg_2 "_list_blogs: Adding file to array:" -_blog_cache_msg_1 "_blog_cache: HASH VALUE:" -_blog_cache_msg_2 "1. _blog_cache:" -_blog_cache_msg_3 "2. _blog_cache: current_cache:" -_blog_cache_msg_4 "3. _blog_cache: new_cache_file:" -_blog_cache_msg_5 "4. _blog_cache: new_current_cache:" -_pages_cache_msg_1 "PAGES HASH VALUE:" -_pages_cache_msg_2 "1. pages_cache:" -_pages_cache_msg_3 "1. _pages_cache: current_cache:" -_pages_cache_msg_4 "2. _pages_cache: pages_file:" -_pages_cache_msg_5 "2. _pages_cache: current_cache:" -_last_updated_msg_1 "_last_updated: Setting date and version in footer" -_last_updated_msg_1 "_last_updated:" -_f_last_updated_msg_1 "_f_last_updated: Setting date and version in footer of file" -_f_last_updated_msg_2 "_f_last_updated:" -_f_last_updated_msg_3 "_f_last_updated: File" -_f_last_updated_msg_3.1 "not found." -_pages_msg_1 "_pages: Running function _pages_cache" -_pages_msg_2 "* You do not have any pages *" -_pages_msg_3 "Generating Pages" -_pages_msg_4 "_pages: pages_array is not empty" -_pages_msg_5 "_pages: Setting Pages template" -_pages_msg_6 "Unable to find the Pages template:" -_pages_msg_7 "_pages: Reading Pages template into pages_tpl" -_pages_msg_9 "_pages: Loading page_content once -" -_pages_msg_10 "_pages: Finding page_title" -_pages_msg_11 "_pages:" -_pages_msg_12 "_pages: Removing #title line from page_content" -_pages_msg_13 "_pages: Running engine on" -_pages_msg_14 "_pages: Checking for #link, #showimg and #ytvideo in page_content" -_pages_msg_15 "_pages: #link is present, run _link: page_content" -_pages_msg_16 "_pages: #showimg is present, run _image: page_content" -_pages_msg_17 "_pages: #ytvideo is present, run _youtube: page_content" -_pages_msg_18 "_pages: Replacing #pagetitle, #tagline and #sitename in pages_tpl" -_pages_msg_19 "_pages: Replacing BODY with page_content in pages_tpl" -_pages_msg_20 "_pages: _last_updated in pages_tpl" -_pages_msg_21 "_pages: Lowercase filenames, always" -_pages_msg_22 "_pages: Running _cleanup" -_pages_msg_23 "- Parsing" -_pages_msg_24 "- blog_in_index =" -_pages_msg_25 "- Printing blog temp file:" -_pages_msg_26 "Updating index.html with new blog posts" -_pages_msg_27 "- Parsing" -_pages_msg_28 "- blog_in_index =" -_pages_msg_29 "- No new or updated Pages found" -_blogs_msg_1 "_blogs: Running function _list_blogs" -_blogs_msg_2 "* You do not have any blogs *" -_blogs_msg_3 "Generating Blogs" -_blogs_msg_4 "_blogs: Running function _blog_cache" -_blogs_msg_5 "Unable to find theme template for Blogs." -_blogs_msg_6 "_blogs: Processing pre-data for" -_blogs_msg_7 "_blogs: Looking for DATE: Found" -_blogs_msg_8 "_blogs: Looking for BLOG_TITLE: Found" -_blogs_msg_9 "* _blogs: DATE metadata missing in" -_blogs_msg_10 "* _blogs: BLOG_TITLE metadata missing in" -_blogs_msg_11 "_blogs: Adding data for" -_blogs_msg_11.1 "to array to export" -_blogs_msg_12 "_blogs: Processing" -_blogs_msg_14 "_blogs: Processing substitutes in" -_blogs_msg_15 "_blogs: Running function" -_blogs_msg_15.1 "for" -_blogs_msg_16 "_blogs: Checking for #link, #showimg and #ytvideo in blog_content" -_blogs_msg_17 "_blogs: #link is present, run _link: blog_content" -_blogs_msg_18 "_blogs: #showimg is present, run _link: blog_content" -_blogs_msg_19 "_blogs: #ytvideo is present, run _link: blog_content" -_blogs_msg_20 "_blogs: Replacing tagline, sitename and pagetitle" -_blogs_msg_21 "_blogs: Creating directory" -_blogs_msg_22 "_blogs: Writing blog to disk:" -_blogs_msg_23 "_blogs: new_updated_blogs=true" -_blogs_msg_24 "- No new or updated Blogs found" -_blogs_msg_25 "* _blogs: Running _blog_idx_for_index" -_blogs_msg_26 "* _blogs: Running _blog_index" -_blog_idx_for_index_msg_1 "- Populating" -_blog_idx_for_index_msg_2 "_blog_idx_for_index: Initiating function" -_blog_idx_for_index_msg_3 "_blog_idx_for_index: BLOG_META_STR_ARRAY:" -_blog_idx_for_index_msg_4 "_blog_idx_for_index: meta_str from BLOG_META_STR_ARRAY from _blogs" -_blog_idx_for_index_msg_5 "_blog_idx_for_index:" -_blog_idx_for_index_msg_6 "_blog_idx_for_index: Iterate over each component and extract information" -_blog_idx_for_index_msg_7 "_blog_idx_for_index: Running" -_blog_idx_for_index_msg_7.1 "on content to catch QStags in Ingress" -_blog_idx_for_index_msg_8 "_blog_idx_for_index: Writing _blog_idx_for_index to file:" -_blog_idx_for_index_msg_9 "_blog_idx_for_index: blog_list_content =" -_blog_index_msg_1 "_blog_index: blog_in_index=" -_blog_index_msg_2 "_blog_index: new_updated_blogs=" -_blog_index_msg_3 "_blog_index: Running function _blog_index" -_blog_index_msg_4 "_blog_index: blog_in_index =" -_blog_index_msg_5 "- Generating Page:" -_blog_index_msg_6 "_blog_index: Replacing sitename and tagline" -_blog_index_msg_7 "_blog_index: Replacing BODY with content of" -_blog_index_msg_8 "_blog_index: Writing" -_blog_index_msg_9 "_blog_index: Content length of blog_index_content:" -_add_blog_list_to_index_msg_1 "_add_blog_list_to_index: Inserting blog list to index.html" -_sitemap_msg_1 "Generating Sitemap" -_sitemap_msg_2 "Sitemap generated at" -_link_msg_1 "_link: URL_MAIN(line):" -_link_msg_2 "_link_ URL:" -_link_msg_3 "_link: Text:" -_image_msg_1 "_image: Processing line:" -_youtube_msg_1 "_youtube: Processing line:" -_cleanup_msg_1 "_cleanup: Cleaning up tags in content" -_html_msg_1 "_html: Converting QStags in content" -_zhtml_msg_1 "_zhtml: Converting QStags in content" -) +# 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 <command> [options]" +info.engine_usage = "Usage: _run_engine <input>" +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 index 61f7b3c..c30f7f3 100644 --- a/include/qsgen2/lang/en_US +++ b/include/qsgen2/lang/en_US @@ -1,117 +1,217 @@ -qsgenlang=( -_qsgen2_msg_2 "- Forced Update: Generating Everything" -_qsgen2_msg_3 "* %SCRIPT_NAME% cannot parse this site. Exiting. *" -_qsgen2_msg_4 "Please install Pandoc." -_qsgen2_msg_5 "No valid generator found. Are you sure you\'ve selected the correct generator in \'config\'?" -_qsgen2_msg_6 "Using the" -_qsgen2_msg_6.1 "-engine for files:" -_qsgen2_msg_7 "- Created by kekePower - 2018-" -_qsgen2_msg_8 "- See" -_qsgen2_msg_8.1 "for more information." -_qsgen2_msg_9 "Contents of the Config file:" -_list_pages_msg_1 "_list_pages: No Pages found with ext" -_list_pages_msg_2 "_list_pages: Adding file to array:" -_list_blogs_msg_1 "_list_blogs: No blog files found." -_list_blogs_msg_2 "_list_blogs: Adding file to array:" -_blog_cache_msg_1 "_blog_cache: HASH VALUE:" -_blog_cache_msg_2 "1. _blog_cache:" -_blog_cache_msg_3 "2. _blog_cache: current_cache:" -_blog_cache_msg_4 "3. _blog_cache: new_cache_file:" -_blog_cache_msg_5 "4. _blog_cache: new_current_cache:" -_pages_cache_msg_1 "PAGES HASH VALUE:" -_pages_cache_msg_2 "1. pages_cache:" -_pages_cache_msg_3 "1. _pages_cache: current_cache:" -_pages_cache_msg_4 "2. _pages_cache: pages_file:" -_pages_cache_msg_5 "2. _pages_cache: current_cache:" -_last_updated_msg_1 "_last_updated: Setting date and version in footer" -_last_updated_msg_1 "_last_updated:" -_f_last_updated_msg_1 "_f_last_updated: Setting date and version in footer of file" -_f_last_updated_msg_2 "_f_last_updated:" -_f_last_updated_msg_3 "_f_last_updated: File" -_f_last_updated_msg_3.1 "not found." -_pages_msg_1 "_pages: Running function _pages_cache" -_pages_msg_2 "* You do not have any pages *" -_pages_msg_3 "Generating Pages" -_pages_msg_4 "_pages: pages_array is not empty" -_pages_msg_5 "_pages: Setting Pages template" -_pages_msg_6 "Unable to find the Pages template:" -_pages_msg_7 "_pages: Reading Pages template into pages_tpl" -_pages_msg_9 "_pages: Loading page_content once -" -_pages_msg_10 "_pages: Finding page_title" -_pages_msg_11 "_pages:" -_pages_msg_12 "_pages: Removing #title line from page_content" -_pages_msg_13 "_pages: Running engine on" -_pages_msg_14 "_pages: Checking for #link, #showimg and #ytvideo in page_content" -_pages_msg_15 "_pages: #link is present, run _link: page_content" -_pages_msg_16 "_pages: #showimg is present, run _image: page_content" -_pages_msg_17 "_pages: #ytvideo is present, run _youtube: page_content" -_pages_msg_18 "_pages: Replacing #pagetitle, #tagline and #sitename in pages_tpl" -_pages_msg_19 "_pages: Replacing BODY with page_content in pages_tpl" -_pages_msg_20 "_pages: _last_updated in pages_tpl" -_pages_msg_21 "_pages: Lowercase filnames, always" -_pages_msg_22 "_pages: Running _cleanup" -_pages_msg_23 "- Parsing" -_pages_msg_24 "- blog_in_index =" -_pages_msg_25 "- Printing blog temp file:" -_pages_msg_26 "Updating index.html with new blog posts" -_pages_msg_27 "- Parsing" -_pages_msg_28 "- blog_in_index =" -_pages_msg_29 "- No new or updated Pages found" -_blogs_msg_1 "_blogs: Running function _list_blogs" -_blogs_msg_2 "* You do not have any blogs *" -_blogs_msg_3 "Generating Blogs" -_blogs_msg_4 "_blogs: Running function _blog_cache" -_blogs_msg_5 "Unable to find theme template for Blogs." -_blogs_msg_6 "_blogs: Processing pre-data for" -_blogs_msg_7 "_blogs: Looking for DATE: Found" -_blogs_msg_8 "_blogs: Looking for BLOG_TITLE: Found" -_blogs_msg_9 "* _blogs: DATE metadata missing in" -_blogs_msg_10 "* _blogs: BLOG_TITLE metadata missing in" -_blogs_msg_11 "_blogs: Adding data for" -_blogs_msg_11.1 "to array to export" -_blogs_msg_12 "_blogs: Processing" -_blogs_msg_14 "_blogs: Processing substitutes in" -_blogs_msg_15 "_blogs: Running function" -_blogs_msg_15_1 "for" -_blogs_msg_16 "_blogs: Checking for #link, #showimg and #ytvideo in blog_content" -_blogs_msg_17 "_blogs: #link is present, run _link: blog_content" -_blogs_msg_18 "_blogs: #showimg is present, run _link: blog_content" -_blogs_msg_19 "_blogs: #ytvideo is present, run _link: blog_content" -_blogs_msg_20 "_blogs: Replacing tagline, sitename and pagetitle" -_blogs_msg_21 "_blogs: Creating directory" -_blogs_msg_22 "_blogs: Writing blog to disk:" -_blogs_msg_23 "_blogs: new_updated_blogs=true" -_blogs_msg_24 "- No new or updated Blogs found" -_blogs_msg_25 "* _blogs: Running _blog_idx_for_index" -_blogs_msg_26 "* _blogs: Running _blog_index" -_blog_idx_for_index_msg_1 "- Populating" -_blog_idx_for_index_msg_2 "_blog_idx_for_index: Initiating function" -_blog_idx_for_index_msg_3 "_blog_idx_for_index: BLOG_META_STR_ARRAY:" -_blog_idx_for_index_msg_4 "_blog_idx_for_index: meta_str from BLOG_META_STR_ARRAY from _blogs" -_blog_idx_for_index_msg_5 "_blog_idx_for_index:" -_blog_idx_for_index_msg_6 "_blog_idx_for_index: Iterate over each component and extract information" -_blog_idx_for_index_msg_7 "_blog_idx_for_index: Running" -_blog_idx_for_index_msg_7.1 "on content to catch QStags in Ingress" -_blog_idx_for_index_msg_8 "_blog_idx_for_index: Writing _blog_idx_for_index to file:" -_blog_idx_for_index_msg_9 "_blog_idx_for_index: blog_list_content =" -_blog_index_msg_1 "_blog_index: blog_in_index=" -_blog_index_msg_2 "_blog_index: new_updated_blogs=" -_blog_index_msg_3 "_blog_index: Running function _blog_index" -_blog_index_msg_4 "_blog_index: blog_in_index =" -_blog_index_msg_5 "- Generating Page:" -_blog_index_msg_6 "_blog_index: Replacing sitename and tagline" -_blog_index_msg_7 "_blog_index: Replacing BODY with content of" -_blog_index_msg_8 "_blog_index: Writing" -_blog_index_msg_9 "_blog_index: Content length of blog_index_content:" -_add_blog_list_to_index_msg_1 "_add_blog_list_to_index: Inserting blog list to index.html" -_sitemap_msg_1 "Generating Sitemap" -_sitemap_msg_2 "Sitemap generated at" -_link_msg_1 "_link: URL_MAIN(line):" -_link_msg_2 "_link_ URL:" -_link_msg_3 "_link: Text:" -_image_msg_1 "_image: Processing line:" -_youtube_msg_1 "_youtube: Processing line:" -_cleanup_msg_1 "_cleanup: Cleaning up tags in content" -_html_msg_1 "_html: Converting QStags in content" -_zhtml_msg_1 "_zhtml: Converting QStags in content" -) +# 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 <command> [options]" +info.engine_usage = "Usage: _run_engine <input>" +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 index b4eb9f9..9a0e825 100644 --- a/include/qsgen2/lang/es_ES +++ b/include/qsgen2/lang/es_ES @@ -1,117 +1,207 @@ -qsgenlang=( -_qsgen2_msg_2 "- Actualización forzada: Generando todo" -_qsgen2_msg_3 "* %SCRIPT_NAME% no puede analizar este sitio. Saliendo. *" -_qsgen2_msg_4 "Por favor, instala Pandoc." -_qsgen2_msg_5 "No se encontró un generador válido. ¿Estás seguro de que has seleccionado el generador correcto en 'config'?" -_qsgen2_msg_6 "Usando el" -_qsgen2_msg_6.1 "-motor para archivos:" -_qsgen2_msg_7 "- Creado por kekePower - 2018-" -_qsgen2_msg_8 "- Ver" -_qsgen2_msg_8.1 "para más información." -_qsgen2_msg_9 "Contenidos del archivo Config:" -_list_pages_msg_1 "_list_pages: No se encontraron páginas con ext" -_list_pages_msg_2 "_list_pages: Añadiendo archivo al array:" -_list_blogs_msg_1 "_list_blogs: No se encontraron archivos de blog." -_list_blogs_msg_2 "_list_blogs: Añadiendo archivo al array:" -_blog_cache_msg_1 "_blog_cache: VALOR HASH:" -_blog_cache_msg_2 "1. _blog_cache:" -_blog_cache_msg_3 "2. _blog_cache: cache_actual:" -_blog_cache_msg_4 "3. _blog_cache: nuevo_archivo_cache:" -_blog_cache_msg_5 "4. _blog_cache: nueva_cache_actual:" -_pages_cache_msg_1 "VALOR HASH PÁGINAS:" -_pages_cache_msg_2 "1. pages_cache:" -_pages_cache_msg_3 "1. _pages_cache: cache_actual:" -_pages_cache_msg_4 "2. _pages_cache: archivo_páginas:" -_pages_cache_msg_5 "2. _pages_cache: cache_actual:" -_last_updated_msg_1 "_last_updated: Estableciendo fecha y versión en el pie de página" -_last_updated_msg_1 "_last_updated:" -_f_last_updated_msg_1 "_f_last_updated: Estableciendo fecha y versión en el pie de página del archivo" -_f_last_updated_msg_2 "_f_last_updated:" -_f_last_updated_msg_3 "_f_last_updated: Archivo" -_f_last_updated_msg_3.1 "no encontrado." -_pages_msg_1 "_pages: Ejecutando función _pages_cache" -_pages_msg_2 "* No tienes ninguna página *" -_pages_msg_3 "Generando Páginas" -_pages_msg_4 "_pages: array_de_páginas no está vacío" -_pages_msg_5 "_pages: Estableciendo plantilla de Páginas" -_pages_msg_6 "No se puede encontrar la plantilla de Páginas:" -_pages_msg_7 "_pages: Leyendo plantilla de Páginas en pages_tpl" -_pages_msg_9 "_pages: Cargando contenido de la página una vez -" -_pages_msg_10 "_pages: Buscando título de página" -_pages_msg_11 "_pages:" -_pages_msg_12 "_pages: Eliminando línea #título del contenido de la página" -_pages_msg_13 "_pages: Ejecutando motor en" -_pages_msg_14 "_pages: Verificando #link, #showimg y #ytvideo en contenido de la página" -_pages_msg_15 "_pages: #link presente, ejecutar _link: contenido de la página" -_pages_msg_16 "_pages: #showimg presente, ejecutar _image: contenido de la página" -_pages_msg_17 "_pages: #ytvideo presente, ejecutar _youtube: contenido de la página" -_pages_msg_18 "_pages: Reemplazando #tituloDePagina, #tagline y #nombreDeSitio en pages_tpl" -_pages_msg_19 "_pages: Reemplazando CUERPO con contenido de la página en pages_tpl" -_pages_msg_20 "_pages: _last_updated en pages_tpl" -_pages_msg_21 "_pages: Nombres de archivo en minúsculas, siempre" -_pages_msg_22 "_pages: Ejecutando _cleanup" -_pages_msg_23 "- Analizando" -_pages_msg_24 "- blog_en_indice =" -_pages_msg_25 "- Imprimiendo archivo temporal del blog:" -_pages_msg_26 "Actualizando index.html con nuevas publicaciones de blog" -_pages_msg_27 "- Analizando" -_pages_msg_28 "- blog_en_indice =" -_pages_msg_29 "- No se encontraron nuevas o actualizadas Páginas" -_blogs_msg_1 "_blogs: Ejecutando función _list_blogs" -_blogs_msg_2 "* No tienes ningún blog *" -_blogs_msg_3 "Generando Blogs" -_blogs_msg_4 "_blogs: Ejecutando función _blog_cache" -_blogs_msg_5 "No se puede encontrar la plantilla de tema para Blogs." -_blogs_msg_6 "_blogs: Procesando datos previos para" -_blogs_msg_7 "_blogs: Buscando FECHA: Encontrado" -_blogs_msg_8 "_blogs: Buscando TÍTULO DEL BLOG: Encontrado" -_blogs_msg_9 "* _blogs: Falta metadatos de FECHA en" -_blogs_msg_10 "* _blogs: Falta metadatos de TÍTULO DEL BLOG en" -_blogs_msg_11 "_blogs: Añadiendo datos para" -_blogs_msg_11.1 "al array para exportar" -_blogs_msg_12 "_blogs: Procesando" -_blogs_msg_14 "_blogs: Procesando sustitutos en" -_blogs_msg_15 "_blogs: Ejecutando función" -_blogs_msg_15.1 "para" -_blogs_msg_16 "_blogs: Verificando #link, #showimg y #ytvideo en contenido del blog" -_blogs_msg_17 "_blogs: #link presente, ejecutar _link: contenido del blog" -_blogs_msg_18 "_blogs: #showimg presente, ejecutar _link: contenido del blog" -_blogs_msg_19 "_blogs: #ytvideo presente, ejecutar _link: contenido del blog" -_blogs_msg_20 "_blogs: Reemplazando tagline, nombreDeSitio y tituloDePagina" -_blogs_msg_21 "_blogs: Creando directorio" -_blogs_msg_22 "_blogs: Escribiendo blog en disco:" -_blogs_msg_23 "_blogs: blogs_actualizados=true" -_blogs_msg_24 "- No se encontraron nuevos o actualizados Blogs" -_blogs_msg_25 "* _blogs: Ejecutando _blog_idx_for_index" -_blogs_msg_26 "* _blogs: Ejecutando _blog_index" -_blog_idx_for_index_msg_1 "- Llenando" -_blog_idx_for_index_msg_2 "_blog_idx_for_index: Iniciando función" -_blog_idx_for_index_msg_3 "_blog_idx_for_index: BLOG_META_STR_ARRAY:" -_blog_idx_for_index_msg_4 "_blog_idx_for_index: meta_str de BLOG_META_STR_ARRAY de _blogs" -_blog_idx_for_index_msg_5 "_blog_idx_for_index:" -_blog_idx_for_index_msg_6 "_blog_idx_for_index: Iterar sobre cada componente y extraer información" -_blog_idx_for_index_msg_7 "_blog_idx_for_index: Ejecutando" -_blog_idx_for_index_msg_7.1 "en contenido para capturar QStags en Ingress" -_blog_idx_for_index_msg_8 "_blog_idx_for_index: Escribiendo _blog_idx_for_index en archivo:" -_blog_idx_for_index_msg_9 "_blog_idx_for_index: contenido_de_lista_de_blogs =" -_blog_index_msg_1 "_blog_index: blog_en_indice=" -_blog_index_msg_2 "_blog_index: blogs_actualizados=" -_blog_index_msg_3 "_blog_index: Ejecutando función _blog_index" -_blog_index_msg_4 "_blog_index: blog_en_indice =" -_blog_index_msg_5 "- Generando Página:" -_blog_index_msg_6 "_blog_index: Reemplazando nombreDeSitio y tagline" -_blog_index_msg_7 "_blog_index: Reemplazando CUERPO con contenido de" -_blog_index_msg_8 "_blog_index: Escribiendo" -_blog_index_msg_9 "_blog_index: Longitud de contenido de blog_index_content:" -_add_blog_list_to_index_msg_1 "_add_blog_list_to_index: Insertando lista de blogs en index.html" -_sitemap_msg_1 "Generando Mapa del Sitio" -_sitemap_msg_2 "Mapa del sitio generado en" -_link_msg_1 "_link: LÍNEA URL_PRINCIPAL:" -_link_msg_2 "_link_ URL:" -_link_msg_3 "_link: Texto:" -_image_msg_1 "_image: Procesando línea:" -_youtube_msg_1 "_youtube: Procesando línea:" -_cleanup_msg_1 "_cleanup: Limpiando etiquetas en contenido" -_html_msg_1 "_html: Convirtiendo QStags en contenido" -_zhtml_msg_1 "_zhtml: Convirtiendo QStags en contenido" -) +# 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 <comando> [opciones]" +info.engine_usage = "Uso: _run_engine <entrada>" +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 index 715061c..7773361 100644 --- a/include/qsgen2/lang/fr_FR +++ b/include/qsgen2/lang/fr_FR @@ -1,117 +1,209 @@ -qsgenlang=( -_qsgen2_msg_2 "- Mise à jour forcée : Génération de tout" -_qsgen2_msg_3 "* %SCRIPT_NAME% ne peut pas analyser ce site. Sortie. *" -_qsgen2_msg_4 "Veuillez installer Pandoc." -_qsgen2_msg_5 "Aucun générateur valide trouvé. Êtes-vous sûr d'avoir sélectionné le bon générateur dans 'config' ?" -_qsgen2_msg_6 "Utilisation du" -_qsgen2_msg_6.1 "-moteur pour les fichiers :" -_qsgen2_msg_7 "- Créé par kekePower - 2018-" -_qsgen2_msg_8 "- Voir" -_qsgen2_msg_8.1 "pour plus d'informations." -_qsgen2_msg_9 "Contenu du fichier Config :" -_list_pages_msg_1 "_list_pages : Aucune page trouvée avec l'extension" -_list_pages_msg_2 "_list_pages : Ajout du fichier au tableau :" -_list_blogs_msg_1 "_list_blogs : Aucun fichier de blog trouvé." -_list_blogs_msg_2 "_list_blogs : Ajout du fichier au tableau :" -_blog_cache_msg_1 "_blog_cache : VALEUR DU HASH :" -_blog_cache_msg_2 "1. _blog_cache :" -_blog_cache_msg_3 "2. _blog_cache : cache_actuel :" -_blog_cache_msg_4 "3. _blog_cache : nouveau_fichier_cache :" -_blog_cache_msg_5 "4. _blog_cache : nouveau_cache_actuel :" -_pages_cache_msg_1 "VALEUR DU HASH DES PAGES :" -_pages_cache_msg_2 "1. cache_des_pages :" -_pages_cache_msg_3 "1. _cache_des_pages : cache_actuel :" -_pages_cache_msg_4 "2. _cache_des_pages : fichier_des_pages :" -_pages_cache_msg_5 "2. _cache_des_pages : cache_actuel :" -_last_updated_msg_1 "_last_updated : Définition de la date et de la version dans le pied de page" -_last_updated_msg_1 "_last_updated :" -_f_last_updated_msg_1 "_f_last_updated : Définition de la date et de la version dans le pied de page du fichier" -_f_last_updated_msg_2 "_f_last_updated :" -_f_last_updated_msg_3 "_f_last_updated : Fichier" -_f_last_updated_msg_3.1 "non trouvé." -_pages_msg_1 "_pages : Exécution de la fonction _cache_des_pages" -_pages_msg_2 "* Vous n'avez aucune page *" -_pages_msg_3 "Génération des Pages" -_pages_msg_4 "_pages : le tableau des pages n'est pas vide" -_pages_msg_5 "_pages : Définition du modèle des Pages" -_pages_msg_6 "Impossible de trouver le modèle des Pages :" -_pages_msg_7 "_pages : Lecture du modèle des Pages dans pages_tpl" -_pages_msg_9 "_pages : Chargement du contenu de la page une fois -" -_pages_msg_10 "_pages : Recherche du titre de la page" -_pages_msg_11 "_pages :" -_pages_msg_12 "_pages : Suppression de la ligne #titre du contenu de la page" -_pages_msg_13 "_pages : Exécution du moteur sur" -_pages_msg_14 "_pages : Vérification de #lien, #montrerimg et #videoyt dans le contenu de la page" -_pages_msg_15 "_pages : #lien présent, exécution de _lien : contenu de la page" -_pages_msg_16 "_pages : #montrerimg présent, exécution de _image : contenu de la page" -_pages_msg_17 "_pages : #videoyt présent, exécution de _youtube : contenu de la page" -_pages_msg_18 "_pages : Remplacement de #titredelapage, #slogan et #nomdusite dans pages_tpl" -_pages_msg_19 "_pages : Remplacement du CORPS par le contenu de la page dans pages_tpl" -_pages_msg_20 "_pages : _dernière_mise_à_jour dans pages_tpl" -_pages_msg_21 "_pages : Noms de fichiers en minuscules, toujours" -_pages_msg_22 "_pages : Exécution de _nettoyage" -_pages_msg_23 "- Analyse" -_pages_msg_24 "- blog_dans_index =" -_pages_msg_25 "- Impression du fichier temporaire du blog :" -_pages_msg_26 "Mise à jour de index.html avec les nouveaux articles de blog" -_pages_msg_27 "- Analyse" -_pages_msg_28 "- blog_dans_index =" -_pages_msg_29 "- Aucune nouvelle page ou mise à jour trouvée" -_blogs_msg_1 "_blogs : Exécution de la fonction _list_blogs" -_blogs_msg_2 "* Vous n'avez aucun blog *" -_blogs_msg_3 "Génération des Blogs" -_blogs_msg_4 "_blogs : Exécution de la fonction _cache_des_blogs" -_blogs_msg_5 "Impossible de trouver le modèle de thème pour les Blogs." -_blogs_msg_6 "_blogs : Traitement des données préliminaires pour" -_blogs_msg_7 "_blogs : Recherche de DATE : Trouvé" -_blogs_msg_8 "_blogs : Recherche de TITRE_DU_BLOG : Trouvé" -_blogs_msg_9 "* _blogs : Donnée de DATE manquante dans" -_blogs_msg_10 "* _blogs : TITRE_DU_BLOG manquant dans" -_blogs_msg_11 "_blogs : Ajout des données pour" -_blogs_msg_11.1 "au tableau pour l'export" -_blogs_msg_12 "_blogs : Traitement" -_blogs_msg_14 "_blogs : Traitement des substituts dans" -_blogs_msg_15 "_blogs : Exécution de la fonction" -_blogs_msg_15.1 "pour" -_blogs_msg_16 "_blogs : Vérification de #lien, #montrerimg et #videoyt dans le contenu du blog" -_blogs_msg_17 "_blogs : #lien présent, exécution de _lien : contenu du blog" -_blogs_msg_18 "_blogs : #montrerimg présent, exécution de _lien : contenu du blog" -_blogs_msg_19 "_blogs : #videoyt présent, exécution de _lien : contenu du blog" -_blogs_msg_20 "_blogs : Remplacement de slogan, nomdusite et titredelapage" -_blogs_msg_21 "_blogs : Création du répertoire" -_blogs_msg_22 "_blogs : Écriture du blog sur le disque :" -_blogs_msg_23 "_blogs : nouveaux_blogs_mis_à_jour=true" -_blogs_msg_24 "- Aucun nouveau blog ou mise à jour trouvée" -_blogs_msg_25 "* _blogs : Exécution de _index_des_blogs_pour_index" -_blogs_msg_26 "* _blogs : Exécution de _index_des_blogs" -_blog_idx_for_index_msg_1 "- Peuplement" -_blog_idx_for_index_msg_2 "_index_des_blogs_pour_index : Initiation de la fonction" -_blog_idx_for_index_msg_3 "_index_des_blogs_pour_index : TABLEAU_DES_META_DU_BLOG :" -_blog_idx_for_index_msg_4 "_index_des_blogs_pour_index : meta_str du TABLEAU_DES_META_DU_BLOG de _blogs" -_blog_idx_for_index_msg_5 "_index_des_blogs_pour_index :" -_blog_idx_for_index_msg_6 "_index_des_blogs_pour_index : Itération sur chaque composant et extraction des informations" -_blog_idx_for_index_msg_7 "_index_des_blogs_pour_index : Exécution de" -_blog_idx_for_index_msg_7.1 "sur le contenu pour attraper les QStags dans l'Ingress" -_blog_idx_for_index_msg_8 "_index_des_blogs_pour_index : Écriture de _index_des_blogs_pour_index dans le fichier :" -_blog_idx_for_index_msg_9 "_index_des_blogs_pour_index : contenu_de_la_liste_des_blogs =" -_blog_index_msg_1 "_index_des_blogs : blog_dans_index=" -_blog_index_msg_2 "_index_des_blogs : nouveaux_blogs_mis_à_jour=" -_blog_index_msg_3 "_index_des_blogs : Exécution de la fonction _index_des_blogs" -_blog_index_msg_4 "_index_des_blogs : blog_dans_index =" -_blog_index_msg_5 "- Génération de la Page :" -_blog_index_msg_6 "_index_des_blogs : Remplacement de nomdusite et slogan" -_blog_index_msg_7 "_index_des_blogs : Remplacement du CORPS par le contenu de" -_blog_index_msg_8 "_index_des_blogs : Écriture" -_blog_index_msg_9 "_index_des_blogs : Longueur du contenu de blog_index_content :" -_add_blog_list_to_index_msg_1 "_add_blog_list_to_index : Insertion de la liste des blogs dans index.html" -_sitemap_msg_1 "Génération du Plan du site" -_sitemap_msg_2 "Plan du site généré à" -_link_msg_1 "_link : URL_PRINCIPALE(ligne) :" -_link_msg_2 "_link_ URL :" -_link_msg_3 "_link : Texte :" -_image_msg_1 "_image : Traitement de la ligne :" -_youtube_msg_1 "_youtube : Traitement de la ligne :" -_cleanup_msg_1 "_cleanup : Nettoyage des tags dans le contenu" -_html_msg_1 "_html : Conversion des QStags dans le contenu" -_zhtml_msg_1 "_zhtml : Conversion des QStags dans le contenu" -) +# 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 <commande> [options]" +info.engine_usage = "Utilisation : _run_engine <entrée>" +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 index b164004..eb7bfc5 100644 --- a/include/qsgen2/lang/nb_NO +++ b/include/qsgen2/lang/nb_NO @@ -1,115 +1,217 @@ -qsgenlang=( -_qsgen2_msg_2 "Tvungen oppdatering: Genererer alt" -_qsgen2_msg_3 "* %SCRIPT_NAME% kan ikke analysere dette nettstedet. Avslutter. *" -_qsgen2_msg_4 "Vennligst installer Pandoc." -_qsgen2_msg_5 "Ingen gyldig generator funnet. Er du sikker på at du har valgt riktig generator i 'config'?" -_qsgen2_msg_6 "Bruker ${generator}-motoren for filer: ${file_ext}" -_qsgen2_msg_7 "- Laget av kekePower - 2018" -_qsgen2_msg_8 "- Se" -_qsgen2_msg_8.1 "for mer informasjon." -_qsgen2_msg_9 "Innhold i Config filen:" -_list_pages_msg_1 "_list_pages: Ingen sider funnet med utvidelse" -_list_pages_msg_2 "_list_pages: Legger til fil i array:" -_list_blogs_msg_3 "_list_blogs: Ingen blogginnlegg funnet." -_list_blogs_msg_4 "_list_blogs: Legger til fil i array:" -_blog_cache_msg_1 "_blog_cache: HASH VERDI:" -_blog_cache_msg_2 "1. _blog_cache:" -_blog_cache_msg_3 "2. _blog_cache: nåværende cache:" -_blog_cache_msg_4 "3. _blog_cache: ny cache-fil:" -_blog_cache_msg_5 "4. _blog_cache: ny nåværende cache:" -_pages_cache_msg_1 "_pages_cache: PAGES HASH VERDI:" -_pages_cache_msg_2 "1. pages_cache:" -_pages_cache_msg_3 "1. _pages_cache: nåværende cache:" -_pages_cache_msg_4 "2. _pages_cache: sidefil:" -_pages_cache_msg_5 "2. _pages_cache: nåværende cache:" -_last_updated_msg_1 "_last_updated: Setter dato og versjon i bunntekst" -_last_updated_msg_1 "_last_updated:" -_f_last_updated_msg_1 "_f_last_updated: Setter dato og versjon i bunntekst for fil" -_f_last_updated_msg_2 "_f_last_updated:" -_f_last_updated_msg_3 "_f_last_updated: Filen" -_f_last_updated_msg_3.1 "ble ikke funnet." -_pages_msg_1 "_pages: Kjører funksjon _pages_cache" -_pages_msg_2 "* Du har ingen sider *" -_pages_msg_3 "Genererer Sider" -_pages_msg_4 "_pages: sidearray er ikke tom" -_pages_msg_5 "_pages: Setter Opp Sider-mal" -_pages_msg_6 "Kan ikke finne Sidemalen:" -_pages_msg_7 "_pages: Leser Sidemalen inn i pages_tpl" -_pages_msg_9 "_pages: Laster sideinnhold en gang - " -_pages_msg_10 "_pages: Finne sidetittel" -_pages_msg_11 "_pages:" -_pages_msg_12 "_pages: Fjerner #tittel linje fra sideinnhold" -_pages_msg_13 "_pages: Kjører motor på" -_pages_msg_14 "_pages: Sjekker for #link, #showimg og #ytvideo i sideinnhold" -_pages_msg_15 "_pages: #link er til stede, kjør _link: sideinnhold" -_pages_msg_16 "_pages: #showimg er til stede, kjør _image: sideinnhold" -_pages_msg_17 "_pages: #ytvideo er til stede, kjør _youtube: sideinnhold" -_pages_msg_18 "_pages: Erstatter #sidetittel, #tagline og #sidenavn i pages_tpl" -_pages_msg_19 "_pages: Erstatter BODY med sideinnhold i pages_tpl" -_pages_msg_20 "_pages: _last_updated i pages_tpl" -_pages_msg_21 "_pages: Filnavn i små bokstaver, alltid" -_pages_msg_22 "_pages: Kjører _cleanup" -_pages_msg_23 "- Analyserer" -_pages_msg_24 "- blog_in_index =" -_pages_msg_25 "- Skriver ut blogg midlertidig fil:" -_pages_msg_26 "Oppdaterer index.html med nye blogginnlegg" -_pages_msg_27 "- Analyserer" -_pages_msg_28 "- blog_in_index =" -_pages_msg_29 "- Ingen nye eller oppdaterte Sider funnet" -_blogs_msg_1 "_blogs: Kjører funksjon _list_blogs" -_blogs_msg_2 "* Du har ingen blogger *" -_blogs_msg_3 "Genererer Blogger" -_blogs_msg_4 "_blogs: Kjører funksjon _blog_cache" -_blogs_msg_5 "Kan ikke finne tema mal for Blogger." -_blogs_msg_6 "_blogs: Behandler forhåndsdata for" -_blogs_msg_7 "_blogs: Leter etter DATO: Funnet" -_blogs_msg_8 "_blogs: Leter etter BLOGGTITTEL: Funnet" -_blogs_msg_9 "* _blogs: DATO-metadata mangler i" -_blogs_msg_10 "* _blogs: BLOGGTITTEL-metadata mangler i" -_blogs_msg_11 "_blogs: Legger til data for" -_blogs_msg_11.1 "til array for eksport" -_blogs_msg_12 "_blogs: Behandler" -_blogs_msg_14 "_blogs: Behandler erstatninger i" -_blogs_msg_15 "_blogs: Kjører funksjon" -_blogs_msg_15.1 "for" -_blogs_msg_16 "_blogs: Sjekker for #link, #showimg og #ytvideo i blogginnhold" -_blogs_msg_17 "_blogs: #link er til stede, kjør _link: blogginnhold" -_blogs_msg_18 "_blogs: #showimg er til stede, kjør _link: blogginnhold" -_blogs_msg_19 "_blogs: #ytvideo er til stede, kjør _link: blogginnhold" -_blogs_msg_20 "_blogs: Erstatter tagline, sitenavn og sidetittel" -_blogs_msg_21 "_blogs: Oppretter katalog" -_blogs_msg_22 "_blogs: Skriver blogg til disk:" -_blogs_msg_23 "_blogs: new_updated_blogs=true" -_blogs_msg_24 "- Ingen nye eller oppdaterte Blogger funnet" -_blogs_msg_25 "* _blogs: Kjører _blog_idx_for_index" -_blogs_msg_26 "* _blogs: Kjører _blog_index" -_blog_idx_for_index_msg_1 "- Fyller" -_blog_idx_for_index_msg_2 "_blog_idx_for_index: Starter funksjon" -_blog_idx_for_index_msg_3 "_blog_idx_for_index: BLOG_META_STR_ARRAY:" -_blog_idx_for_index_msg_4 "_blog_idx_for_index: meta_str fra BLOG_META_STR_ARRAY fra _blogs" -_blog_idx_for_index_msg_5 "_blog_idx_for_index:" -_blog_idx_for_index_msg_6 "_blog_idx_for_index: Går gjennom hver komponent og trekker ut informasjon" -_blog_idx_for_index_msg_7 "_blog_idx_for_index: Kjører" -_blog_idx_for_index_msg_7.1 "på innhold for å fange QStags i Ingress" -_blog_idx_for_index_msg_8 "_blog_idx_for_index: Skriver _blog_idx_for_index til fil:" -_blog_idx_for_index_msg_9 "_blog_idx_for_index: blog_list_content =" -_blog_index_msg_1 "_blog_index: blog_in_index=" -_blog_index_msg_2 "_blog_index: new_updated_blogs=" -_blog_index_msg_3 "_blog_index: Kjører funksjon _blog_index" -_blog_index_msg_4 "_blog_index: blog_in_index = " -_blog_index_msg_5 "- Genererer Side:" -_blog_index_msg_6 "_blog_index: Erstatter sitenavn og tagline" -_blog_index_msg_7 "_blog_index: Erstatter BODY med innhold fra" -_blog_index_msg_8 "_blog_index: Skriver" -_add_blog_list_to_index_msg_1 "_add_blog_list_to_index: Setter inn bloggliste i index.html" -_sitemap_msg_1 "Genererer Nettsidekart" -_sitemap_msg_2 "Nettsidekart generert på" -_link_msg_1 "_link: HOVED URL-LINJE:" -_link_msg_2 "_link_ URL:" -_link_msg_3 "_link: Tekst:" -_image_msg_1 "_image: Behandler linje:" -_youtube_msg_1 "_youtube: Behandler linje:" -_cleanup_msg_1 "_cleanup: Renser opp i merker i innhold" -_html_msg_1 "_html: Konverterer QStags i innhold" -_zhtml_msg_1 "_zhtml: Konverterer QStags i innhold" -) +# 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 <kommando> [alternativer]" +info.engine_usage = "Bruk: _run_engine <inndata>" +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/qsgen2 b/qsgen2 index 0f75a39..df659ab 100755 --- a/qsgen2 +++ b/qsgen2 @@ -1,4 +1,4 @@ -#!/usr/bin/zsh +#!/usr/bin/env zsh ############################################################################### ############################################################################### @@ -16,14 +16,287 @@ ############################################################################### ############################################################################### -VERSION="0.5.1" # Sun-2025-05-18 +VERSION="0.6.0" # Sun-2025-05-18 QSGEN="Quick Site Generator 2" -# Set to true or false -# This will show debug information from every function in this script -# You can also set debug=true in a single function if you want to debug only that specific one. +# 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 </dev/null | head -n1 | grep -oE '[0-9]+\.[0-9]+(\.[0-9]+)?' + ;; + pandoc) + "$tool" --version | head -n1 | grep -oE '[0-9]+\.[0-9]+(\.[0-9]+)?' + ;; + *) + "$tool" --version 2>&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 @@ -33,197 +306,387 @@ 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 [[ -f $(pwd)/site.conf ]]; then - if (${globaldebug}); then _msg debug "Config file found and sourced: $(pwd)/site.conf"; fi - if zini $(pwd)/site.conf; then - config_loaded=true - else - _msg info "Failed to load site.conf" - fi -fi - -# Fallback to 'config' if site.conf not found or failed to load -if [[ ${config_loaded} == false && -f $(pwd)/config ]]; then - if (${globaldebug}); then _msg debug "Legacy config file found and sourced: $(pwd)/config"; fi - _msg info "Warning: Using legacy 'config' file. Consider renaming to 'site.conf'" - if zini $(pwd)/config; then - config_loaded=true - else - _msg info "Failed to load legacy config file" - fi -fi - -# Exit if no config file was loaded -if [[ ${config_loaded} == false ]]; then - _msg error "Cannot find or load configuration file." - _msg info "Please create 'site.conf' in your project directory." - _msg info "You can use 'config.example' as a template." +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 -# Load language as defined in config -typeset -A qsgenlang -lang_found=false -for dir in $fpath; do - if [[ -f "${dir}/${config[project_lang]}" ]]; then - # echo "Language file: ${dir}/${config[project_lang]}" - source "${dir}/${config[project_lang]}" - lang_found=true - break +# 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 -done -if [[ ${lang_found} == "false" ]]; then - # Fall back to en_US if defined language isn't found - echo "Defined language, ${config[project_lang]}, not found. Using en_US." - source "${HOME}/bin/include/qsgen2/lang/en_US" - 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 "=== Loaded Configuration ===" + _msg debug i18n debug.loaded_config for key value in ${(kv)config}; do - _msg debug "${key}: ${value}" + _msg debug i18n debug.config_key_value "$key" "$value" done - _msg debug "===========================" - - # Also show raw config file content - local config_file="$(pwd)/site.conf" - [[ ! -f "${config_file}" ]] && config_file="$(pwd)/config" - if [[ -f "${config_file}" ]]; then - _msg debug "=== Raw Config File ===" - cat "${config_file}" | grep -v '^\s*#' | while read -r line; do - _msg debug "${line}" - done - _msg debug "======================" - fi + _msg debug i18n debug.config_end fi -function _msg() { - local type=$1 - shift # Remove the first argument so $@ now contains only keys or additional strings - - local full_msg="" - for arg in "$@"; do - if [[ -n "${qsgenlang[$arg]}" ]]; then - full_msg+="${qsgenlang[$arg]}" - else - full_msg+="$arg" - fi - done - - # Determine the color based on the type - local color="${end}" # Default to no color if type is unrecognized - case $type in - std) color="${green}" ;; - info) color="${yellow}" ;; - debug) color="${red}" ;; - other) color="${bold_yellow}" ;; - sub) color="${magenta}" ;; - main) color="${white}${green_bg}" ;; - esac - - # Use printf with %b to allow backslash escape interpretation - printf "${color}%b${end}\n" "${full_msg}" -} - -function _version() { - _msg info "_qsgen2_msg_7" "-$(strftime "%Y")" - echo "${yellow}- https://github.com/kekePower/qsgen2/${end}" - _msg info "_qsgen2_msg_8" " '${1} help' " "_qsgen2_msg_8.1" - exit -} - -function _help() { - # This will also be translated some time in the future - echo "This is where I'll write the Help documentation." - exit -} - -if [[ "$1" == "version" || "$1" == "-v" || "$1" == "--version" ]]; then - _version ${0:t} -elif [[ "$1" == "help" || "$1" == "-h" || "$1" == "--help" ]]; then - _help ${0:t} -fi - -# Define cache files for blogs and pages -blog_cache_file="${config[project_root]}/.blog_cache" -pages_cache_file="${config[project_root]}/.pages_cache" - -# Validate required configuration -required_configs=( - "project_generator" - "project_root" - "site_root" - "site_theme" - "site_name" - "site_url" - "project_lang" -) - -# Check for missing required configurations -missing_configs=() -for key in ${required_configs[@]}; do - if [[ -z "${config[$key]}" ]]; then - missing_configs+=("$key") - fi -done - -if [[ ${#missing_configs[@]} -gt 0 ]]; then - _msg error "Missing required configuration values:" - for key in ${missing_configs[@]}; do - _msg error "- $key" - done - exit 1 -fi - -# Check if we're in a git repository -if [[ -d $(pwd)/.git ]]; then - _msg info "Warning: Running in a git repository directory. Make sure this is intended." - _msg info "If you want to generate the site, run from the project root directory." - exit 1 +# 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 -mkdir -p "${config[project_root]}" -mkdir -p "${config[site_root]}" +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 -# We define the variable 'engine' based on what's in the 'config' file. -if [[ ${config[project_generator]} == "native" ]]; then - # Usage: ${engine} ${1} - Where 1 is the file you want to convert +# 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 [[ ! -f /usr/local/bin/pandoc ]]; then - _msg other "_qsgen2_msg_4" - _msg other "https://github.com/jgm/pandoc/releases" - exit + if ! command -v pandoc &>/dev/null; then + _msg error i18n pandoc.install + _msg info i18n pandoc.download + exit 1 else - # Usage: ${engine} ${1} - Where 1 is the file you want parsed - engine="/usr/local/bin/pandoc" - engine_opts= + engine="pandoc" export file_ext="md" fi else - _msg debug "_qsgen2_msg_5" - exit + _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 <input> - local debug=false + # This function runs the appropriate engine on the input file - if [[ ${config[project_generator]} == "native" ]]; then - ${engine} ${1} + 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 - echo "${1} | ${engine} ${engine_opts}" + 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 debug "ERROR running engine: ${engine}!" - _msg info "Usage: _run_engine <input>" - exit + _msg error i18n error.unknown_generator "${config[project_generator]}" + return 1 fi } @@ -384,7 +847,7 @@ function _blog_cache() { _list_blogs # Create an associative array for the blog cache - typeset -A blog_cache + typeset -gA config_cache # Load the existing blog cache if [[ -f $blog_cache_file ]]; then @@ -437,7 +900,7 @@ function _pages_cache() { fi # Create an associative array for the pages cache - typeset -A pages_cache + typeset -gA config_cache _list_pages @@ -734,158 +1197,220 @@ function _blogs() { if (( ${#make_blog_array[@]} > 0 )); then - # Declare the array to hold metadata strings for each blog - BLOG_META_STR_ARRAY=() - - # Regular blog creation process - + # 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 - - for blog in "${make_blog_array[@]}"; do - if (${debug}) _msg info "*************************************************************************" - if (${debug}) _msg info "**************************FOR LOOP START*********************************" - if (${debug}) _msg info "*************************************************************************" - if (${debug}) _msg debug "${0:t}_msg_6" " ${blog}" - - local content="$(<"${blog}")" - local sdate btitle ingress body blog_index blog_dir blog_url + + # 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" - # Initialize variables to track if DATE and BLOG_TITLE are found - local date_found=false - local title_found=false - - # Process content line by line - while IFS= read -r line - do - # Check for the DATE line - if [[ "${line}" == "DATE "* ]]; then - if (${debug}) _msg debug "${0:t}_msg_7" - date_found=true - fi - # Check for the BLOG_TITLE line - if [[ "${line}" == "BLOG_TITLE "* ]]; then - if (${debug}) _msg debug "${0:t}_msg_8" - title_found=true - fi - # If both DATE and BLOG_TITLE are found, no need to continue checking - if [[ "${date_found}" == true && "${title_found}" == true ]]; then - break - fi - done <<< "${content}" - - # Check if DATE or BLOG_TITLE metadata is missing and log message - if [[ "${date_found}" == false ]]; then - if (${debug}) _msg debug "${0:t}_msg_9" " ${blog}." - continue # Skip this file and move to the next - fi - if [[ "${title_found}" == false ]]; then - if (${debug}) _msg debug "${0:t}_msg_10" " ${blog}." - continue # Skip this file and move to the next - fi - - # Extract blog information - sdate=( $( echo ${content} | grep DATE | sed "s|DATE\ ||" | sed "s|\-|\ |g" ) ) - if [[ ${config[project_generator]} == "native" ]]; then - if (${debug}) _msg debug "* qstags: Fetching BLOG_TITLE" - while IFS= read -r line; do - if [[ "$line" == "BLOG_TITLE "* ]]; then - btitle="${line#BLOG_TITLE }" - break - fi - done <<< "$content" - elif [[ ${config[project_generator]} == "markdown" ]]; then - if (${debug}) _msg debug "* markdown: Fetching BLOG_TITLE" - while IFS= read -r line; do - if [[ "$line" == \#* ]]; then - btitle="${line#\#}" # Remove the first '#' character - btitle="${btitle#\#}" # Remove the second '#' character if present - btitle="${btitle#"${btitle%%[![:space:]]*}"}" # Trim leading whitespace - break # Exit the loop after finding the first heading - fi - done <<< "$content" - fi - if (${debug}) _msg debug "* Fetching INGRESS" - ingress=$( echo ${content} | sed "s/'/\\\'/g" | xargs | grep -Po "#INGRESS_START\K(.*?)#INGRESS_STOP" | sed "s|\ \#INGRESS_STOP||" | sed "s|^\ ||" ) - if (${debug}) _msg debug "* Fetching BODY" - body=$( echo ${content} | sed "s/'/\\\'/g" | xargs | grep -Po "#BODY_START\K(.*?)#BODY_STOP" | sed "s|\ \#BODY_STOP||" | sed "s|^\ ||" ) - - blog_index=$(echo "${btitle:l}" | sed 's/ /_/g; s/,//g; s/\.//g; s/://g; s/[()]//g') - - blog_dir="/blog/${sdate[2]}/${sdate[3]:l}/${sdate[4]}" - blog_url="${blog_dir}/${blog_index}.html" - - if (${debug}) _msg debug "${0:t}_msg_11" " ${blog} " "${0:t}_msg_11.1" - - # Concatenate all metadata into a single string for the current blog - local metadata_str="SDATE: ${sdate[@]}||BTITLE: ${btitle}||INGRESS: ${ingress}||URL: ${blog_url}" - # Append this metadata string to the array - BLOG_META_STR_ARRAY+=("${metadata_str}") - - if (${debug}) _msg debug "${0:t}_msg_12" " ${blog}" - - _msg std " - ${btitle}" - - # Prepare the blog template - if (${debug}) _msg debug "${0:t}_msg_14" " ${blog}" - 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 \ - ") - 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]}}" - - if (${debug}) _msg debug "${0:t}_msg_15" " ${engine} " "${0:t}_msg_15_1" " ${blog}" - blog_content=$( _run_engine "${blog_content}" ) - # Look for links, images and videos and convert them if present. - if (${debug}) _msg debug "${0:t}_msg_16" - if [[ $( echo ${blog_content} | grep \#link ) ]]; then - if (${debug}) _msg debug "${0:t}_msg_17" - blog_content=$(_link "${blog_content}") - fi - if [[ $( echo ${blog_content} | grep \#showimg ) ]]; then - if (${debug}) _msg debug "${0:t}_msg_18" - blog_content=$(_image "${blog_content}") - fi - if [[ $( echo ${blog_content} | grep \#linkimg ) ]]; then - if (${debug}) _msg debug "${0:t}_msg_19" - blog_content=$(_linkimg "${blog_content}") - fi - if [[ $( echo ${blog_content} | grep \#ytvideo ) ]]; then - if (${debug}) _msg debug "${0:t}_msg_20" - blog_content=$(_youtube "${blog_content}") - fi - - # Replace every #tagline in blog_content - if (${debug}) _msg debug "${0:t}_msg_21" - blog_content=$( echo ${blog_content} | perl -pe "s|#tagline|${config[site_tagline]}|gs; s|#sitename|${config[site_name]}|gs; s|#pagetitle|${page_title}|gs" ) + # 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 - if (${debug}) _msg debug "* Running _last_updated" - blog_content=$(_last_updated "${blog_content}") - if (${debug}) _msg debug "* Running _cleanup" - blog_content=$(_cleanup "${blog_content}") - - # Create directory if it doesn't exist - if (${debug}) _msg debug "${0:t}_msg_22" " ${config[site_root]}${blog_dir}" - [[ ! -d "${config[site_root]}/${blog_dir}" ]] && mkdir -p "${config[site_root]}/${blog_dir}" - - # Write to file - if (${debug}) _msg debug "${0:t}_msg_23" " ${config[site_root]}${blog_url}" - echo "${blog_content}" > "${config[site_root]}${blog_url}" - - unset sdate btitle ingress body blog_index blog_dir blog_url - + # 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" @@ -1435,8 +1960,228 @@ function _p_qstags() { } -function _qstags() { +############################################################################### +# 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/#GT/>/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/</#LT/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 diff --git a/config.example b/site.conf.example similarity index 100% rename from config.example rename to site.conf.example diff --git a/tools/extract_messages.sh b/tools/extract_messages.sh new file mode 100755 index 0000000..d631b47 --- /dev/null +++ b/tools/extract_messages.sh @@ -0,0 +1,144 @@ +#!/usr/bin/env zsh + +# Script to extract and organize user-facing strings from the codebase + +set -e + +# Configuration +SOURCE_DIR="$(dirname "$0")/.." +LANG_DIR="${SOURCE_DIR}/include/qsgen2/lang" +OUTPUT_FILE="${LANG_DIR}/extracted_messages.txt" + +# Create output directory if it doesn't exist +mkdir -p "$(dirname "$OUTPUT_FILE")" + +# Initialize output file +cat > "$OUTPUT_FILE" << 'EOF' +# Quick Site Generator 2 - Extracted Messages +# This file contains all user-facing strings extracted from the codebase +# Generated on: $(date) + +# Format: +# [message_id] = "message" +# Where message_id is in the format: category_subject_description +# Example: error_file_not_found = "File not found: %s" + +# Categories: +# - config: Configuration related messages +# - file: File operation messages +# - build: Build process messages +# - blog: Blog system messages +# - page: Page system messages +# - error: Error messages +# - warning: Warning messages +# - info: Informational messages +# - debug: Debug messages + +# Message Dictionary +[messages] + +EOF + +# Function to add a message to the output file +add_message() { + local category="$1" + local subject="$2" + local description="$3" + local message="$4" + + # Generate message ID + local msg_id="${category}_${subject}_${description}" + + # Clean up the message ID + msg_id=$(echo "$msg_id" | tr '[:upper:]' '[:lower:]' | tr ' ' '_' | sed 's/[^a-z0-9_]/_/g' | sed 's/__*/_/g' | sed 's/^_//;s/_$//') + + # Add to output file + echo "${msg_id} = \"${message}\"" >> "$OUTPUT_FILE" +} + +# Extract messages from _msg calls +echo "# Extracting messages from _msg calls..." + +grep -r --include="*.zsh" --include="*.sh" -h "_msg " "$SOURCE_DIR" | \ + grep -v '^\s*#' | \ + grep -v '^\s*$' | \ + while read -r line; do + # Extract message type and content + msg_type=$(echo "$line" | awk -F'"' '{print $1}' | awk '{print $NF}' | tr -d ' ') + msg_content=$(echo "$line" | sed -E 's/.*_msg[[:space:]]+[^[:space:]]+[[:space:]]+["]([^"]+)["].*/\1/') + + # Skip if we couldn't extract content + if [[ "$msg_content" == "$line" ]]; then + continue + fi + + # Determine category based on message type + case "$msg_type" in + error) + category="error" + ;; + warning) + category="warning" + ;; + info|other) + category="info" + ;; + debug) + category="debug" + ;; + *) + category="info" + ;; + esac + + # Generate a description from the message content + description=$(echo "$msg_content" | \ + head -n 1 | \ + tr '[:upper:]' '[:lower:]' | \ + sed 's/[^a-z0-9 ]/ /g' | \ + sed 's/ */ /g' | \ + cut -c1-30 | \ + tr ' ' '_' | \ + sed 's/_$//') + + # Add the message + add_message "$category" "general" "$description" "$msg_content" +done + +# Extract messages from echo/print statements +echo "# Extracting messages from echo/print statements..." + +grep -r --include="*.zsh" --include="*.sh" -h -E 'echo|printf|print' "$SOURCE_DIR" | \ + grep -v '^\s*#' | \ + grep -v '^\s*$' | \ + grep -v '\\n' | \ + grep -v '\$\|`' | \ + grep -E '".*[a-z].*"' | \ + while read -r line; do + # Extract message content + msg_content=$(echo "$line" | grep -o '"[^"]*"' | head -n 1 | tr -d '"') + + # Skip if no content + if [[ -z "$msg_content" ]]; then + continue + fi + + # Skip common debug/technical messages + if [[ "$msg_content" =~ ^[^a-zA-Z]*$ ]]; then + continue + fi + + # Add as an info message + description=$(echo "$msg_content" | \ + head -n 1 | \ + tr '[:upper:]' '[:lower:]' | \ + sed 's/[^a-z0-9 ]/ /g' | \ + sed 's/ */ /g' | \ + cut -c1-30 | \ + tr ' ' '_' | \ + sed 's/_$//') + + add_message "info" "general" "$description" "$msg_content" +done + +echo "Message extraction complete. Review the output in $OUTPUT_FILE" diff --git a/tools/migrate_messages.sh b/tools/migrate_messages.sh new file mode 100755 index 0000000..74be2c5 --- /dev/null +++ b/tools/migrate_messages.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env zsh + +# Script to help migrate message strings to the new format + +set -e + +# Configuration +SOURCE_DIR="$(dirname "$0")/.." +LANG_DIR="${SOURCE_DIR}/include/qsgen2/lang" +OUTPUT_FILE="${LANG_DIR}/message_migration.txt" + +# Create output directory if it doesn't exist +mkdir -p "$(dirname "$OUTPUT_FILE")" + +# Initialize output file +cat > "$OUTPUT_FILE" << EOF +# Quick Site Generator 2 - Message Migration +# This file helps migrate from old message format to the new format +# Generated on: $(date) +# +# Format: +# OLD_ID = "message" +# NEW_ID = "new.message.id" +# +# [Additional notes] + +EOF + +# Find all _msg calls in the codebase +echo "# Messages from _msg calls" >> "$OUTPUT_FILE" +grep -r --include="*.zsh" --include="*.sh" -h "_msg " "$SOURCE_DIR" | \ + grep -o "_msg \w\+ \"[^\"]\+" | \ + sort -u | \ + while read -r line; do + # Extract message type and content + msg_type=$(echo "$line" | awk '{print $2}') + msg_content=$(echo "$line" | cut -d'"' -f2) + + # Generate a message ID based on content + msg_id=$(echo "$msg_content" | \ + tr '[:upper:]' '[:lower:]' | \ + sed 's/[^a-z0-9]/_/g' | \ + sed 's/__*/_/g' | \ + sed 's/^_//;s/_$//') + + # Add to output file + echo "# $line" >> "$OUTPUT_FILE" + echo "msg_${msg_id} = \"${msg_content}\"" >> "$OUTPUT_FILE" + echo >> "$OUTPUT_FILE" +done + +# Find all existing message IDs in language files +echo -e "\n# Existing message IDs in language files" >> "$OUTPUT_FILE" +find "$LANG_DIR" -type f -name "*.en" -o -name "en_*" | while read -r langfile; do + echo "## From $(basename "$langfile"):" >> "$OUTPUT_FILE" + grep -o '"_\?[a-zA-Z0-9_]\+"' "$langfile" | \ + sort -u | \ + sed 's/^"//;s/"$//' >> "$OUTPUT_FILE" + echo >> "$OUTPUT_FILE" +done + +echo "Migration file created at: $OUTPUT_FILE" +echo "Please review and update the message IDs as needed." diff --git a/tools/migrate_messages_to_system.sh b/tools/migrate_messages_to_system.sh new file mode 100755 index 0000000..1378b1f --- /dev/null +++ b/tools/migrate_messages_to_system.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env zsh + +# Script to migrate hardcoded messages to the message system + +set -e + +# Configuration +SOURCE_DIR="$(dirname "$0")/.." +LANG_FILE="${SOURCE_DIR}/include/qsgen2/lang/qsgen2.en" +TEMP_FILE="${SOURCE_DIR}/.qsgen2.tmp" + +# Create a backup of the original file +backup_file() { + local file="$1" + local backup="${file}.bak.$(date +%s)" + cp "$file" "$backup" + echo "Created backup at: $backup" +} + +# Replace a message in the code +replace_message() { + local old_msg="$1" + local new_key="$2" + local file="$3" + + # Escape special characters for sed + local escaped_old=$(printf '%s\n' "$old_msg" | sed 's/[&/\^$*.]/\\&/g') + local escaped_new="_msg i18n \"$new_key\"" + + # Handle messages with parameters + if [[ "$old_msg" == *"%s"* ]]; then + escaped_new="${escaped_new} \"\${1:-\"\"}\"" + fi + + # Replace in file + sed -i "s/_msg \(info\|warning\|error\|debug\|other\) \"$escaped_old\"/$escaped_new/g" "$file" +} + +# Process a single file +process_file() { + local file="$1" + echo "Processing file: $file" + + # Create a backup + backup_file "$file" + + # Replace messages + while IFS= read -r line; do + if [[ "$line" =~ ^([a-z.]+)[[:space:]]*=[[:space:]]*"([^"]+)" ]]; then + local key="${match[1]}" + local msg="${match[2]}" + + # Skip comments and empty lines + [[ "$key" == "#"* ]] && continue + [[ -z "$key" ]] && continue + + # Replace in file + replace_message "$msg" "$key" "$file" + fi + done < "$LANG_FILE" +} + +# Find all shell scripts in the project +find "$SOURCE_DIR" -type f \( -name "*.zsh" -o -name "*.sh" \) -not -path "*/.*" | while read -r file; do + process_file "$file" +done + +echo "Migration complete. Please review the changes and test the application."