diff --git a/Plaster/Plaster.psm1 b/Plaster/Plaster.psm1 index 2dd3e8c..5b86aa8 100644 --- a/Plaster/Plaster.psm1 +++ b/Plaster/Plaster.psm1 @@ -1,76 +1,12 @@ # spell-checker:ignore Multichoice Assigments -# Import localized data -data LocalizedData { - # culture="en-US" - ConvertFrom-StringData @' - DestPath_F1=Destination path: {0} - ErrorFailedToLoadStoreFile_F1=Failed to load the default value store file: '{0}'. - ErrorProcessingDynamicParams_F1=Failed to create dynamic parameters from the template's manifest file. Template-based dynamic parameters will not be available until the error is corrected. The error was: {0} - ErrorTemplatePathIsInvalid_F1=The TemplatePath parameter value must refer to an existing directory. The specified path '{0}' does not. - ErrorUnencryptingSecureString_F1=Failed to unencrypt value for parameter '{0}'. - ErrorPathDoesNotExist_F1=Cannot find path '{0}' because it does not exist. - ErrorPathMustBeRelativePath_F2=The path '{0}' specified in the {1} directive in the template manifest cannot be an absolute path. Change the path to a relative path. - ErrorPathMustBeUnderDestPath_F2=The path '{0}' must be under the specified DestinationPath '{1}'. - ExpressionInvalid_F2=The expression '{0}' is invalid or threw an exception. Error: {1} - ExpressionNonTermErrors_F2=The expression '{0}' generated error output - {1} - ExpressionExecError_F2=PowerShell expression failed execution. Location: {0}. Error: {1} - ExpressionErrorLocationFile_F2=<{0}> attribute '{1}' - ExpressionErrorLocationModify_F1= attribute '{0}' - ExpressionErrorLocationNewModManifest_F1= attribute '{0}' - ExpressionErrorLocationParameter_F2= name='{0}', attribute '{1}' - ExpressionErrorLocationRequireModule_F2= name='{0}', attribute '{1}' - ExpressionInvalidCondition_F3=The Plaster manifest condition '{0}' failed. Location: {1}. Error: {2} - InterpolationError_F3=The Plaster manifest attribute value '{0}' failed string interpolation. Location: {1}. Error: {2} - FileConflict=Plaster file conflict - ManifestFileMissing_F1=The Plaster manifest file '{0}' was not found. - ManifestMissingDocElement_F2=The Plaster manifest file '{0}' is missing the document element. It should be specified as . - ManifestMissingDocTargetNamespace_F2=The Plaster manifest file '{0}' is missing or has an invalid target namespace on the document element. It should be specified as . - ManifestPlasterVersionNotSupported_F2=The template file '{0}' specifies a plasterVersion of {1} which is greater than the installed version of Plaster. Update the Plaster module and try again. - ManifestSchemaInvalidAttrValue_F5=Invalid '{0}' attribute value '{1}' on '{2}' element in file '{3}'. Error: {4} - ManifestSchemaInvalidCondition_F3=Invalid condition '{0}' in file '{1}'. Error: {2} - ManifestSchemaInvalidChoiceDefault_F3=Invalid default attribute value '{0}' for parameter '{1}' in file '{2}'. The default value must specify a zero-based integer index that corresponds to the default choice. - ManifestSchemaInvalidMultichoiceDefault_F3=Invalid default attribute value '{0}' for parameter '{1}' in file '{2}'. The default value must specify one or more zero-based integer indexes in a comma separated list that correspond to the default choices. - ManifestSchemaInvalidRequireModuleAttrs_F2=The requireModule attribute 'requiredVersion' for module '{0}' in file '{1}' cannot be used together with either the 'minimumVersion' or 'maximumVersion' attribute. - ManifestSchemaValidationError_F2=Plaster manifest schema error in file '{0}'. Error: {1} - ManifestSchemaVersionNotSupported_F2=The template's manifest schema version ({0}) in file '{1}' requires a newer version of Plaster. Update the Plaster module and try again. - ManifestErrorReading_F1=Error reading Plaster manifest: {0} - ManifestNotValid_F1=The Plaster manifest '{0}' is not valid. - ManifestNotValidVerbose_F1=The Plaster manifest '{0}' is not valid. Specify -Verbose to see the specific schema errors. - ManifestNotWellFormedXml_F2=The Plaster manifest '{0}' is not a well-formed XML file. {1} - ManifestWrongFilename_F1=The Plaster manifest filename '{0}' is not valid. The value of the Path argument must refer to a file named 'plasterManifest.xml' or 'plasterManifest_.xml'. Change the Plaster manifest filename and then try again. - MissingParameterPrompt_F1= - NewModManifest_CreatingDir_F1=Creating destination directory for module manifest: {0} - OpConflict=Conflict - OpCreate=Create - OpForce=Force - OpIdentical=Identical - OpMissing=Missing - OpModify=Modify - OpUpdate=Update - OpVerify=Verify - OverwriteFile_F1=Overwrite {0} - ParameterTypeChoiceMultipleDefault_F1=Parameter name {0} is of type='choice' and can only have one default value. - RequireModuleVerified_F2=The required module {0}{1} is already installed. - RequireModuleMissing_F2=The required module {0}{1} was not found. - RequireModuleMinVersion_F1=minimum version: {0} - RequireModuleMaxVersion_F1=maximum version: {0} - RequireModuleRequiredVersion_F1=required version: {0} - ShouldCreateNewPlasterManifest=Create Plaster manifest - ShouldProcessCreateDir=Create directory - ShouldProcessExpandTemplate=Expand template file - ShouldProcessNewModuleManifest=Create new module manifest - TempFileOperation_F1={0} into temp file before copying to destination - TempFileTarget_F1=temp file for '{0}' - TestPlasterNoXmlSchemaValidationWarning=The version of .NET Core that PowerShell is running on does not support XML schema-based validation. Test-PlasterManifest will operate in "limited validation" mode primarily verifying the specified manifest file is well-formed XML. For full, XML schema-based validation, run this command on Windows PowerShell. - UnrecognizedParametersElement_F1=Unrecognized manifest parameters child element: {0}. - UnrecognizedParameterType_F2=Unrecognized parameter type '{0}' on parameter name '{1}'. - UnrecognizedContentElement_F1=Unrecognized manifest content child element: {0}. -'@ -} - # Import localized data with improved error handling try { - Microsoft.PowerShell.Utility\Import-LocalizedData LocalizedData -FileName 'Plaster.Resources.psd1' -ErrorAction SilentlyContinue + $importLocalizedDataSplat = @{ + BindingVariable = 'LocalizedData' + FileName = 'Plaster.Resources.psd1' + ErrorAction = 'SilentlyContinue' + } + Microsoft.PowerShell.Utility\Import-LocalizedData @importLocalizedDataSplat } catch { Write-Warning "Failed to import localized data: $_" } diff --git a/Plaster/Private/Start-ProcessFile.ps1 b/Plaster/Private/Start-ProcessFile.ps1 index 52f5bd8..dd4dd30 100644 --- a/Plaster/Private/Start-ProcessFile.ps1 +++ b/Plaster/Private/Start-ProcessFile.ps1 @@ -1,12 +1,42 @@ # Processes both the and directives. function Start-ProcessFile { + <# + .SYNOPSIS + Processes the and directives in a Plaster template. + + .DESCRIPTION + This function processes the and directives in a + Plaster template. + It resolves the source and destination paths, checks conditions, expands + file source specifications, + + .PARAMETER Node + The XML node representing the or directive. + + .EXAMPLE + Start-ProcessFile -Node $fileNode + + Processes the specified file node, resolving paths and handling conditions. + .NOTES + This function is part of the Plaster module and is used internally to handle + file processing in templates. + #> [CmdletBinding(SupportsShouldProcess = $true)] param( [ValidateNotNull()] $Node ) - $srcRelPath = Resolve-AttributeValue $Node.source (Get-ErrorLocationFileAttrVal $Node.localName source) - $dstRelPath = Resolve-AttributeValue $Node.destination (Get-ErrorLocationFileAttrVal $Node.localName destination) + $resolveAttributeValueSplat = @{ + Value = $Node.source + Location = (Get-ErrorLocationFileAttrVal $Node.localName source) + } + $srcRelPath = Resolve-AttributeValue @resolveAttributeValueSplat + + $resolveAttributeValueSplat = @{ + Value = $Node.destination + Location = (Get-ErrorLocationFileAttrVal $Node.localName destination) + } + $dstRelPath = Resolve-AttributeValue @resolveAttributeValueSplat $condition = $Node.condition if ($condition -and !(Test-ConditionAttribute $condition "'<$($Node.LocalName)>'")) { diff --git a/Plaster/en-US/Plaster.Resources.psd1 b/Plaster/en-US/Plaster.Resources.psd1 index b443c27..798a876 100644 --- a/Plaster/en-US/Plaster.Resources.psd1 +++ b/Plaster/en-US/Plaster.Resources.psd1 @@ -1,41 +1,42 @@ +#### WARNING: This file is auto-generated from Plaster.Resources.en-US.json. +#### Do not edit this file directly. Instead, update the source JSON file in the i18n directory. # Localized PlasterResources.psd1 - +# This file was generated from Plaster.Resources.en-US.json using a Psake task. ConvertFrom-StringData @' -###PSLOC DestPath_F1=Destination path: {0} ErrorFailedToLoadStoreFile_F1=Failed to load the default value store file: '{0}'. -ErrorProcessingDynamicParams_F1=Failed to create dynamic parameters from the template's manifest file. Template-based dynamic parameters will not be available until the error is corrected. The error was: {0} -ErrorTemplatePathIsInvalid_F1=The TemplatePath parameter value must refer to an existing directory. The specified path '{0}' does not. -ErrorUnencryptingSecureString_F1=Failed to unencrypt value for parameter '{0}'. ErrorPathDoesNotExist_F1=Cannot find path '{0}' because it does not exist. ErrorPathMustBeRelativePath_F2=The path '{0}' specified in the {1} directive in the template manifest cannot be an absolute path. Change the path to a relative path. ErrorPathMustBeUnderDestPath_F2=The path '{0}' must be under the specified DestinationPath '{1}'. -ExpressionInvalid_F2=The expression '{0}' is invalid or threw an exception. Error: {1} -ExpressionNonTermErrors_F2=The expression '{0}' generated error output - {1} -ExpressionExecError_F2=PowerShell expression failed execution. Location: {0}. Error: {1} +ErrorProcessingDynamicParams_F1=Failed to create dynamic parameters from the template's manifest file. Template-based dynamic parameters will not be available until the error is corrected. The error was: {0} +ErrorTemplatePathIsInvalid_F1=The TemplatePath parameter value must refer to an existing directory. The specified path '{0}' does not. +ErrorUnencryptingSecureString_F1=Failed to unencrypt value for parameter '{0}'. ExpressionErrorLocationFile_F2=<{0}> attribute '{1}' ExpressionErrorLocationModify_F1= attribute '{0}' ExpressionErrorLocationNewModManifest_F1= attribute '{0}' ExpressionErrorLocationParameter_F2= name='{0}', attribute '{1}' ExpressionErrorLocationRequireModule_F2= name='{0}', attribute '{1}' +ExpressionExecError_F2=PowerShell expression failed execution. Location: {0}. Error: {1} +ExpressionInvalid_F2=The expression '{0}' is invalid or threw an exception. Error: {1} ExpressionInvalidCondition_F3=The Plaster manifest condition '{0}' failed. Location: {1}. Error: {2} -InterpolationError_F3=The Plaster manifest attribute value '{0}' failed string interpolation. Location: {1}. Error: {2} +ExpressionNonTermErrors_F2=The expression '{0}' generated error output - {1} FileConflict=Plaster file conflict +InterpolationError_F3=The Plaster manifest attribute value '{0}' failed string interpolation. Location: {1}. Error: {2} +ManifestErrorReading_F1=Error reading Plaster manifest: {0} ManifestFileMissing_F1=The Plaster manifest file '{0}' was not found. ManifestMissingDocElement_F2=The Plaster manifest file '{0}' is missing the document element. It should be specified as . ManifestMissingDocTargetNamespace_F2=The Plaster manifest file '{0}' is missing or has an invalid target namespace on the document element. It should be specified as . +ManifestNotValid_F1=The Plaster manifest '{0}' is not valid. +ManifestNotValidVerbose_F1=The Plaster manifest '{0}' is not valid. Specify -Verbose to see the specific schema errors. +ManifestNotWellFormedXml_F2=The Plaster manifest '{0}' is not a well-formed XML file. {1} ManifestPlasterVersionNotSupported_F2=The template file '{0}' specifies a plasterVersion of {1} which is greater than the installed version of Plaster. Update the Plaster module and try again. ManifestSchemaInvalidAttrValue_F5=Invalid '{0}' attribute value '{1}' on '{2}' element in file '{3}'. Error: {4} -ManifestSchemaInvalidCondition_F3=Invalid condition '{0}' in file '{1}'. Error: {2} ManifestSchemaInvalidChoiceDefault_F3=Invalid default attribute value '{0}' for parameter '{1}' in file '{2}'. The default value must specify a zero-based integer index that corresponds to the default choice. +ManifestSchemaInvalidCondition_F3=Invalid condition '{0}' in file '{1}'. Error: {2} ManifestSchemaInvalidMultichoiceDefault_F3=Invalid default attribute value '{0}' for parameter '{1}' in file '{2}'. The default value must specify one or more zero-based integer indexes in a comma separated list that correspond to the default choices. ManifestSchemaInvalidRequireModuleAttrs_F2=The requireModule attribute 'requiredVersion' for module '{0}' in file '{1}' cannot be used together with either the 'minimumVersion' or 'maximumVersion' attribute. ManifestSchemaValidationError_F2=Plaster manifest schema error in file '{0}'. Error: {1} ManifestSchemaVersionNotSupported_F2=The template's manifest schema version ({0}) in file '{1}' requires a newer version of Plaster. Update the Plaster module and try again. -ManifestErrorReading_F1=Error reading Plaster manifest: {0} -ManifestNotValid_F1=The Plaster manifest '{0}' is not valid. -ManifestNotValidVerbose_F1=The Plaster manifest '{0}' is not valid. Specify -Verbose to see the specific schema errors. -ManifestNotWellFormedXml_F2=The Plaster manifest '{0}' is not a well-formed XML file. {1} ManifestWrongFilename_F1=The Plaster manifest filename '{0}' is not valid. The value of the Path argument must refer to a file named 'plasterManifest.xml' or 'plasterManifest_.xml'. Change the Plaster manifest filename and then try again. MissingParameterPrompt_F1= NewModManifest_CreatingDir_F1=Creating destination directory for module manifest: {0} @@ -49,11 +50,11 @@ OpUpdate=Update OpVerify=Verify OverwriteFile_F1=Overwrite {0} ParameterTypeChoiceMultipleDefault_F1=Parameter name {0} is of type='choice' and can only have one default value. -RequireModuleVerified_F2=The required module {0}{1} is already installed. -RequireModuleMissing_F2=The required module {0}{1} was not found. -RequireModuleMinVersion_F1=minimum version: {0} RequireModuleMaxVersion_F1=maximum version: {0} +RequireModuleMinVersion_F1=minimum version: {0} +RequireModuleMissing_F2=The required module {0}{1} was not found. RequireModuleRequiredVersion_F1=required version: {0} +RequireModuleVerified_F2=The required module {0}{1} is already installed. ShouldCreateNewPlasterManifest=Create Plaster manifest ShouldProcessCreateDir=Create directory ShouldProcessExpandTemplate=Expand template file @@ -61,8 +62,7 @@ ShouldProcessNewModuleManifest=Create new module manifest TempFileOperation_F1={0} into temp file before copying to destination TempFileTarget_F1=temp file for '{0}' TestPlasterNoXmlSchemaValidationWarning=The version of .NET Core that PowerShell is running on does not support XML schema-based validation. Test-PlasterManifest will operate in "limited validation" mode primarily verifying the specified manifest file is well-formed XML. For full, XML schema-based validation, run this command on Windows PowerShell. +UnrecognizedContentElement_F1=Unrecognized manifest content child element: {0}. UnrecognizedParametersElement_F1=Unrecognized manifest parameters child element: {0}. UnrecognizedParameterType_F2=Unrecognized parameter type '{0}' on parameter name '{1}'. -UnrecognizedContentElement_F1=Unrecognized manifest content child element: {0}. -###PSLOC '@ diff --git a/README.md b/README.md index 894eab2..0521e34 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,9 @@ ![Platform Support](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-blue) ![PowerShell Support](https://img.shields.io/badge/PowerShell-5.1%2B%20%7C%207.x-blue) -> **Plaster 2.0 is here!** Fully modernized for PowerShell 7.x with complete cross-platform support while maintaining 100% backward compatibility with existing templates. +> **Plaster 2.0 is here!** Fully modernized for PowerShell 7.x with complete +> cross-platform support while maintaining 100% backward compatibility with +> existing templates. ## What's New in 2.0 @@ -18,25 +20,33 @@ ## Overview -Plaster is a template-based file and project generator written in PowerShell. Its purpose is to streamline the creation of PowerShell module projects, Pester tests, DSC configurations, and more. File generation is performed using crafted templates which allow users to fill in details and choose from options to get their desired output. +Plaster is a template-based file and project generator written in PowerShell. +Its purpose is to streamline the creation of PowerShell module projects, Pester +tests, DSC configurations, and more. File generation is performed using crafted +templates which allow users to fill in details and choose from options to get +their desired output. Think of Plaster as [Yeoman](http://yeoman.io) for the PowerShell community. ## Key Features ### Template-Based Generation -- **Flexible Templates**: Create files, directories, and entire project structures + +- **Flexible Templates**: Create files, directories, and entire project + structures - **Parameter Substitution**: Dynamic content based on user input - **Conditional Logic**: Smart templates that adapt based on choices - **Localization Support**: Multi-language template support ### Cross-Platform Ready + - **Universal Compatibility**: Works on Windows, Linux, and macOS - **Path Normalization**: Automatic handling of platform-specific paths - **Encoding Support**: UTF-8 with proper BOM handling - **Line Ending Management**: Consistent line endings across platforms ### Developer Friendly + - **Modern PowerShell**: Leverages PowerShell 5.1+ and 7.x features - **Rich Validation**: Comprehensive parameter and template validation - **Detailed Logging**: Configurable logging for debugging and monitoring @@ -45,6 +55,7 @@ Think of Plaster as [Yeoman](http://yeoman.io) for the PowerShell community. ## Installation ### PowerShell Gallery (Recommended) + ```powershell # Install for current user Install-Module Plaster -Scope CurrentUser @@ -57,9 +68,12 @@ Update-Module Plaster ``` ### Manual Installation -Download the latest release from our [Releases](https://github.com/PowerShellOrg/Plaster/releases) page. + +Download the latest release from our +[Releases](https://github.com/PowerShellOrg/Plaster/releases) page. ### Development Version + ```powershell # Clone and build from source git clone https://github.com/PowerShellOrg/Plaster.git @@ -70,6 +84,7 @@ cd Plaster ## Quick Start ### 1. Explore Available Templates + ```powershell # List built-in templates Get-PlasterTemplate @@ -82,6 +97,7 @@ Get-PlasterTemplate -Name "*Module*" -Tag "PowerShell" ``` ### 2. Create a New Project + ```powershell # Interactive mode - Plaster will prompt for parameters Invoke-Plaster -TemplatePath BuiltinTemplate -DestinationPath C:\MyNewProject @@ -98,6 +114,7 @@ Invoke-Plaster @templateParams ``` ### 3. Create Your Own Template + ```powershell # Generate a new template manifest New-PlasterManifest -TemplateName 'MyTemplate' -TemplateType 'Project' @@ -109,22 +126,29 @@ Test-PlasterManifest -Path .\plasterManifest.xml ## Documentation ### Core Documentation + - **[Getting Started Guide](docs/en-US/about_Plaster.help.md)** - Learn the basics -- **[Creating Templates](docs/en-US/about_Plaster_CreatingAManifest.help.md)** - Template authoring guide +- **[Creating Templates](docs/en-US/about_Plaster_CreatingAManifest.help.md)** - + Template authoring guide - **[Cmdlet Reference](docs/en-US/Plaster.md)** - Complete API documentation - **[Migration Guide](docs/Migration-v2.md)** - Upgrading from v1.x ### Learning Resources + - **[Template Gallery](docs/Templates.md)** - Community templates - **[Best Practices](docs/BestPractices.md)** - Template design guidelines - **[Examples](examples/)** - Sample templates and usage - **[FAQ](docs/FAQ.md)** - Common questions and answers ### Video Resources -- [Working with Plaster Presentation](https://youtu.be/16CYGTKH73U) by David Christian + +- [Working with Plaster Presentation](https://youtu.be/16CYGTKH73U) by David + Christian ### Blog Posts -- [Working with Plaster](http://overpoweredshell.com/Working-with-Plaster/) by David Christian + +- [Working with Plaster](http://overpoweredshell.com/Working-with-Plaster/) by + David Christian ## Template Structure @@ -138,6 +162,7 @@ MyTemplate/ ``` ### Basic Manifest Example + ```xml @@ -167,6 +192,7 @@ MyTemplate/ ## Usage Examples ### Creating a PowerShell Module + ```powershell # Use the built-in module template $moduleParams = @{ @@ -181,12 +207,14 @@ Invoke-Plaster @moduleParams ``` ### Creating a Custom Script + ```powershell # Create a new script from template Invoke-Plaster -TemplatePath .\MyScriptTemplate -DestinationPath .\Scripts -ScriptName 'ProcessData' -Author 'Jane Smith' ``` ### Batch Project Creation + ```powershell # Create multiple projects from a template $projects = @('ProjectA', 'ProjectB', 'ProjectC') @@ -198,12 +226,14 @@ foreach ($project in $projects) { ## Development and Testing ### Prerequisites + - PowerShell 5.1 or higher - Pester 5.0+ (for testing) - PSScriptAnalyzer (for code quality) - InvokeBuild (for building) ### Building from Source + ```powershell # Clone the repository git clone https://github.com/PowerShellOrg/Plaster.git @@ -223,6 +253,7 @@ cd Plaster ``` ### Running Tests + ```powershell # Run all tests Invoke-Pester @@ -251,22 +282,27 @@ Plaster 2.0 provides full cross-platform support: ### Platform-Specific Considerations #### Windows + - Full XML schema validation support - Uses `$env:LOCALAPPDATA\Plaster` for parameter storage #### Linux + - Uses `$HOME/.local/share/plaster` for parameter storage - Follows XDG Base Directory Specification #### macOS + - Uses `$HOME/.plaster` for parameter storage - Full Unicode support for file names ## Contributing -We welcome contributions! Please see our [Contributing Guidelines](CONTRIBUTING.md) for details. +We welcome contributions! Please see our +[Contributing Guidelines](CONTRIBUTING.md) for details. ### Ways to Contribute + - **Report Bugs** - File issues with detailed reproduction steps - **Suggest Features** - Share ideas for new functionality - **Improve Documentation** - Help make our docs better @@ -274,6 +310,7 @@ We welcome contributions! Please see our [Contributing Guidelines](CONTRIBUTING. - **Create Templates** - Share useful templates with the community ### Development Setup + 1. Fork the repository 2. Create a feature branch 3. Make your changes @@ -284,11 +321,13 @@ We welcome contributions! Please see our [Contributing Guidelines](CONTRIBUTING. ## Compatibility ### PowerShell Versions + - ✅ **PowerShell 5.1** (Windows PowerShell) - ✅ **PowerShell 7.0+** (Cross-platform) - ❌ **PowerShell 3.0-5.0** (No longer supported) ### Breaking Changes from v1.x + - Minimum PowerShell version increased to 5.1 - Default encoding changed to UTF8-NoBOM - Pester 5.x required for development/testing @@ -297,29 +336,44 @@ We welcome contributions! Please see our [Contributing Guidelines](CONTRIBUTING. ## Support ### Getting Help + - **Documentation** - Check our comprehensive docs -- **Discussions** - Ask questions in [GitHub Discussions](https://github.com/PowerShellOrg/Plaster/discussions) -- **Issues** - Report bugs in [GitHub Issues](https://github.com/PowerShellOrg/Plaster/issues) -- **Community** - Join the PowerShell community on [Discord](https://discord.gg/powershell) +- **Discussions** - Ask questions in + [GitHub Discussions](https://github.com/PowerShellOrg/Plaster/discussions) +- **Issues** - Report bugs in + [GitHub Issues](https://github.com/PowerShellOrg/Plaster/issues) +- **Community** - Join the PowerShell community on + [Discord](https://discord.gg/powershell) ### Commercial Support + For enterprise support and consulting, contact the maintainers through GitHub. ## License -This project is licensed under the [MIT License](LICENSE) - see the license file for details. +This project is licensed under the [MIT License](LICENSE) - see the license file +for details. ## Acknowledgments ### Maintainers -- [Jeff Hicks](https://github.com/jdhitsolutions) - [@jeffhicks](http://twitter.com/jeffhicks) -- [James Petty](https://github.com/psjamess) - [@PSJamesP](http://twitter.com/PSJamesP) + +- [Jeff Hicks](https://github.com/jdhitsolutions) - + [@jeffhicks](http://twitter.com/jeffhicks) +- [James Petty](https://github.com/psjamess) - + [@PSJamesP](http://twitter.com/PSJamesP) ### Contributors -Special thanks to all the community contributors who have helped make Plaster better. See our [Contributors](https://github.com/PowerShellOrg/Plaster/contributors) page for the full list. + +Special thanks to all the community contributors who have helped make Plaster +better. See our +[Contributors](https://github.com/PowerShellOrg/Plaster/contributors) page for +the full list. ### Legacy -Originally created by the PowerShell team at Microsoft and transferred to PowerShell.org in 2020 to ensure continued community development. + +Originally created by the PowerShell team at Microsoft and transferred to +PowerShell.org in 2020 to ensure continued community development. --- @@ -327,4 +381,4 @@ Originally created by the PowerShell team at Microsoft and transferred to PowerS [![PowerShell Gallery](https://img.shields.io/powershellgallery/dt/Plaster)](https://www.powershellgallery.com/packages/Plaster/) [![GitHub stars](https://img.shields.io/github/stars/PowerShellOrg/Plaster)](https://github.com/PowerShellOrg/Plaster/stargazers) -[![GitHub forks](https://img.shields.io/github/forks/PowerShellOrg/Plaster)](https://github.com/PowerShellOrg/Plaster/network/members) \ No newline at end of file +[![GitHub forks](https://img.shields.io/github/forks/PowerShellOrg/Plaster)](https://github.com/PowerShellOrg/Plaster/network/members) diff --git a/i18n/Plaster.Resources.en-US.json b/i18n/Plaster.Resources.en-US.json new file mode 100644 index 0000000..525a976 --- /dev/null +++ b/i18n/Plaster.Resources.en-US.json @@ -0,0 +1,64 @@ +{ + "ManifestSchemaInvalidChoiceDefault_F3": "Invalid default attribute value '{0}' for parameter '{1}' in file '{2}'. The default value must specify a zero-based integer index that corresponds to the default choice.", + "RequireModuleMinVersion_F1": "minimum version: {0}", + "ManifestPlasterVersionNotSupported_F2": "The template file '{0}' specifies a plasterVersion of {1} which is greater than the installed version of Plaster. Update the Plaster module and try again.", + "ManifestSchemaInvalidMultichoiceDefault_F3": "Invalid default attribute value '{0}' for parameter '{1}' in file '{2}'. The default value must specify one or more zero-based integer indexes in a comma separated list that correspond to the default choices.", + "ManifestMissingDocTargetNamespace_F2": "The Plaster manifest file '{0}' is missing or has an invalid target namespace on the document element. It should be specified as .", + "ManifestNotValid_F1": "The Plaster manifest '{0}' is not valid.", + "ShouldCreateNewPlasterManifest": "Create Plaster manifest", + "NewModManifest_CreatingDir_F1": "Creating destination directory for module manifest: {0}", + "ManifestErrorReading_F1": "Error reading Plaster manifest: {0}", + "ErrorUnencryptingSecureString_F1": "Failed to unencrypt value for parameter '{0}'.", + "ParameterTypeChoiceMultipleDefault_F1": "Parameter name {0} is of type='choice' and can only have one default value.", + "OpConflict": "Conflict", + "ManifestSchemaInvalidRequireModuleAttrs_F2": "The requireModule attribute 'requiredVersion' for module '{0}' in file '{1}' cannot be used together with either the 'minimumVersion' or 'maximumVersion' attribute.", + "ErrorPathMustBeUnderDestPath_F2": "The path '{0}' must be under the specified DestinationPath '{1}'.", + "ErrorProcessingDynamicParams_F1": "Failed to create dynamic parameters from the template's manifest file. Template-based dynamic parameters will not be available until the error is corrected. The error was: {0}", + "ShouldProcessExpandTemplate": "Expand template file", + "OpMissing": "Missing", + "ExpressionNonTermErrors_F2": "The expression '{0}' generated error output - {1}", + "RequireModuleMaxVersion_F1": "maximum version: {0}", + "RequireModuleVerified_F2": "The required module {0}{1} is already installed.", + "ErrorPathMustBeRelativePath_F2": "The path '{0}' specified in the {1} directive in the template manifest cannot be an absolute path. Change the path to a relative path.", + "OpCreate": "Create", + "OpVerify": "Verify", + "ErrorTemplatePathIsInvalid_F1": "The TemplatePath parameter value must refer to an existing directory. The specified path '{0}' does not.", + "ExpressionErrorLocationParameter_F2": " name='{0}', attribute '{1}'", + "TestPlasterNoXmlSchemaValidationWarning": "The version of .NET Core that PowerShell is running on does not support XML schema-based validation. Test-PlasterManifest will operate in \"limited validation\" mode primarily verifying the specified manifest file is well-formed XML. For full, XML schema-based validation, run this command on Windows PowerShell.", + "ManifestNotValidVerbose_F1": "The Plaster manifest '{0}' is not valid. Specify -Verbose to see the specific schema errors.", + "ShouldProcessCreateDir": "Create directory", + "OpIdentical": "Identical", + "ExpressionInvalid_F2": "The expression '{0}' is invalid or threw an exception. Error: {1}", + "UnrecognizedContentElement_F1": "Unrecognized manifest content child element: {0}.", + "ManifestNotWellFormedXml_F2": "The Plaster manifest '{0}' is not a well-formed XML file. {1}", + "ExpressionExecError_F2": "PowerShell expression failed execution. Location: {0}. Error: {1}", + "OpForce": "Force", + "ManifestSchemaInvalidCondition_F3": "Invalid condition '{0}' in file '{1}'. Error: {2}", + "OverwriteFile_F1": "Overwrite {0}", + "InterpolationError_F3": "The Plaster manifest attribute value '{0}' failed string interpolation. Location: {1}. Error: {2}", + "FileConflict": "Plaster file conflict", + "ExpressionErrorLocationFile_F2": "<{0}> attribute '{1}'", + "ManifestSchemaVersionNotSupported_F2": "The template's manifest schema version ({0}) in file '{1}' requires a newer version of Plaster. Update the Plaster module and try again.", + "RequireModuleMissing_F2": "The required module {0}{1} was not found.", + "UnrecognizedParameterType_F2": "Unrecognized parameter type '{0}' on parameter name '{1}'.", + "ManifestSchemaInvalidAttrValue_F5": "Invalid '{0}' attribute value '{1}' on '{2}' element in file '{3}'. Error: {4}", + "ManifestFileMissing_F1": "The Plaster manifest file '{0}' was not found.", + "OpModify": "Modify", + "ErrorFailedToLoadStoreFile_F1": "Failed to load the default value store file: '{0}'.", + "ExpressionErrorLocationModify_F1": " attribute '{0}'", + "RequireModuleRequiredVersion_F1": "required version: {0}", + "ShouldProcessNewModuleManifest": "Create new module manifest", + "TempFileTarget_F1": "temp file for '{0}'", + "DestPath_F1": "Destination path: {0}", + "ManifestWrongFilename_F1": "The Plaster manifest filename '{0}' is not valid. The value of the Path argument must refer to a file named 'plasterManifest.xml' or 'plasterManifest_.xml'. Change the Plaster manifest filename and then try again.", + "MissingParameterPrompt_F1": "", + "TempFileOperation_F1": "{0} into temp file before copying to destination", + "OpUpdate": "Update", + "UnrecognizedParametersElement_F1": "Unrecognized manifest parameters child element: {0}.", + "ExpressionInvalidCondition_F3": "The Plaster manifest condition '{0}' failed. Location: {1}. Error: {2}", + "ExpressionErrorLocationRequireModule_F2": " name='{0}', attribute '{1}'", + "ExpressionErrorLocationNewModManifest_F1": " attribute '{0}'", + "ManifestSchemaValidationError_F2": "Plaster manifest schema error in file '{0}'. Error: {1}", + "ManifestMissingDocElement_F2": "The Plaster manifest file '{0}' is missing the document element. It should be specified as .", + "ErrorPathDoesNotExist_F1": "Cannot find path '{0}' because it does not exist." +} diff --git a/i18n/README.md b/i18n/README.md new file mode 100644 index 0000000..87a87f8 --- /dev/null +++ b/i18n/README.md @@ -0,0 +1,47 @@ +# Internationalization (i18n) Files + +⚠️ **IMPORTANT: DO NOT EDIT THESE FILES DIRECTLY** ⚠️ + +## About These Files + +The files in this directory contain localized resources for the Plaster +PowerShell module. These files are automatically generated and updated by +[Crowdin](https://crowdin.com/), our localization management platform. + +## What's In This Directory + +- `*.json` files: Localized string resources for different languages and cultures +- Translation files are named using the format: `Plaster.Resources..json` + +## How Localization Works + +1. **Source strings** are maintained in the main codebase +2. **Crowdin** automatically syncs these strings for translation +3. **Translators** use the Crowdin platform to provide translations +4. **Updated translations** are automatically pushed back to this repository + via Crowdin integration + +## Contributing Translations + +If you'd like to help translate Plaster: + +1. Visit our Crowdin project page +2. Request access to contribute translations +3. Use the Crowdin web interface to submit translations +4. Your contributions will be automatically included in future releases + +## For Maintainers + +- Never edit the `*.json` files in this directory directly +- Changes to source strings should be made in the main PowerShell code +- The source of truth for necessary strings will be + `Plaster\en-US\Plaster.Resources.psd1`. +- The `en-US` json file is exported by running the `ExportLocalizationJson` + build task. i.e. `.\build.ps1 -Task ExportLocalizationJson` +- Crowdin will automatically detect and sync new or modified strings +- The Crowdin integration will create pull requests with updated translations + +## Questions? + +If you have questions about the localization process, please open an issue +in the main repository. diff --git a/psakeFile.ps1 b/psakeFile.ps1 index 89f48dc..9b3311f 100644 --- a/psakeFile.ps1 +++ b/psakeFile.ps1 @@ -18,3 +18,51 @@ $InformationPreference = 'Continue' Task Default -Depends Test Task Test -FromModule PowerShellBuild -MinimumVersion '0.6.1' + +# Export-LocalizationJson: Convert all Plaster.Resources.psd1 files to JSON for CrowdIn +Task ExportLocalizationJson { + $importLocalizedDataSplat = @{ + BindingVariable = 'LocalizedData' + FileName = 'Plaster.Resources.psd1' + ErrorAction = 'SilentlyContinue' + } + # Import the en-US localized data + Microsoft.PowerShell.Utility\Import-LocalizedData @importLocalizedDataSplat + # Create the i18n directory if it doesn't exist + if (-not (Test-Path "i18n")) { + New-Item -Path "i18n" -ItemType Directory | Out-Null + } + + # Convert the localized data to JSON and save it + $jsonContent = $LocalizedData | ConvertTo-Json -Depth 10 + $jsonPath = Join-Path "i18n" "Plaster.Resources.en-US.json" + Set-Content -Path $jsonPath -Value $jsonContent -Encoding UTF8 +} + +# Convert all i18n/Plaster.Resources..json files to psd1 for runtime +Task GenerateLocalizationPsd1 { + $jsonFiles = Get-ChildItem -Path "i18n" -Filter "Plaster.Resources.*.json" -File + foreach ($jsonFile in $jsonFiles) { + if ($jsonFile.Name -match "^Plaster\.Resources\.([^.]+)\.json$") { + $locale = $matches[1] + $psd1Dir = Join-Path "Plaster" $locale + if (-not (Test-Path $psd1Dir)) { New-Item -Path $psd1Dir -ItemType Directory | Out-Null } + $psd1Path = Join-Path $psd1Dir "Plaster.Resources.psd1" + $data = Get-Content $jsonFile.FullName | ConvertFrom-Json + $stringData = ($data.PSObject.Properties | Sort-Object Name | ForEach-Object { + "$($_.Name)=$($_.Value)" + }) -join "`n" + $psd1Content = @" +#### WARNING: This file is auto-generated from $($jsonFile.Name). +#### Do not edit this file directly. Instead, update the source JSON file in the i18n directory. +# Localized PlasterResources.psd1 +# This file was generated from $($jsonFile.Name) using a Psake task. +ConvertFrom-StringData @' +$stringData +'@ +"@ + Set-Content $psd1Path $psd1Content -Encoding UTF8 + Write-Host "Imported $jsonFile to $psd1Path" + } + } +}