-
Notifications
You must be signed in to change notification settings - Fork 13
Website translations documentation
The document is going to explain the whole process around the translation of the model YAML files, deploying the website with different translations, troubleshooting. It will start by giving brief overview of the whole process and then it will go into more technical details.
- Overview
- Github ↔ Crowdin integration
- Language repositories
- Core model repository
- Website
- How to ...
Translation is happening via Crowdin https://crowdin.com/project/owasp-samm
Each language has its own directory in the Crowdin project. Those YAML files are pushed from each language repository and when the translation is finished they are pushed back to the same repository.
Each translation is having its own Github repository (e.g. https://github.com/owaspsamm/i18n-FR/). Each repository has branches with the different versions of the model files (e.g trans_2.0). When the translations are ready and they are pushed to the branch, a Github Action can be run (from the Actions tab in the Github repository) which will convert the YAML files to markdown files and push them to "markdown" branch in the current language repository.
Later when the website 'deploy' CI/CD job is run Hugo (the website framework) will collect all translations (from the 'markdown' branches) from the different predefined repositories. Then the website will be deployed with the different languages.
We are using Github Crowdin integration (https://support.crowdin.com/github-integration/, https://support.crowdin.com/github-integration-sb/)
This requires that each translation has a branch with the source English files (e.g. src_2.0) and a branch with resulted translations (e.g. trans_2.0). The translated file will be pushed to the second branch (trans_2.0). Crowdin configuration (of the repository) happens in crowdin.yaml file which is telling what files to use and the resulting file names.
Crowdin will automatically open a pull requests in the repository to merge the resulted branch into the source branch (pull request is not mandatory to be accepted)
Each language should have it own repository (e.g. https://github.com/owaspsamm/i18n-FR/) This repository should contain a branch with the translated YAML files (e.g. trans_2.0). The original English files can be uploaded manually or a Github Action can be used to pull them.
This action is optional, but you will have to manually clone the English YAML model files when you want to start new translation version.
This is happening with shared workflow (https://docs.github.com/en/actions/sharing-automations/reusing-workflows) from the core repository. This is made so we don't duplicate the same logic across all language repositories (i.e. DRY).
# This is the workflow which will call the shared workflow which will clone the english model files
name: Get English files
# Controls when the workflow will run
on:
workflow_dispatch:
inputs:
source_branch:
description: 'The core repository branch to pull translation YAML files from (e.g. develop)'
required: true
source_folder:
description: 'The folder in the core branch to pull translation YAML files from (e.g. model)'
required: true
new_branch_name:
description: 'The name of the new branch to create in this repository with the pulled files (e.g. trans_2.0.8)'
required: true
jobs:
shared-workflow:
uses: owaspsamm/core/.github/workflows/reusable-create-translation-branch.yml@438ef84c34d08befb5cd413a3344d1e6e1f75e9e
with:
source_branch: ${{inputs.source_branch}}
source_folder: ${{inputs.source_folder}}
new_branch_name: ${{inputs.new_branch_name}}
This action accepts 3 parameters. Source branch where the files are located, source folder where the files are located and the new branch name which will be created in the language repository.
owaspsamm/core/.github/workflows/eusable-create-translation-branch.yml@438ef84c34d08befb5cd413a3344d1e6e1f75e9e
This line will use reusable-create-translation-branch.yml workflow in owaspsamm/core repository. The last part is the commit hash of the most recent version of the shared workflow. If a new version of the workflow is released the commit hash have to be changed in each language repository so they use the newest version of the workflow.
This repository should contain Github Action that is going to be used to convert the YAML files to markdown files. All the language repositories are going to use a "shared workflow" file from the core repository (https://docs.github.com/en/actions/sharing-automations/reusing-workflows). This is made so we don't duplicate the same logic across all language repositories (i.e. DRY).
# This is example language action workflow file
name: Generate web markdown
# Controls when the workflow will run
on:
workflow_dispatch:
inputs:
branch:
description: 'Enter branch to use YAML files from'
required: true
type: string
model_folder:
description: 'Enter folder to use YAML files from'
required: true
type: string
jobs:
shared-workflow-name:
uses: owaspsamm/core/.github/workflows/reusable-yaml-process.yml@438ef84c34d08befb5cd413a3344d1e6e1f75e9e
with:
language: fr
branch: ${{inputs.branch}}
model_folder: ${{inputs.model_folder}}
This file will result in Github Action that is going to ask for two parameters.
The file presented is calling the shared workflow file in the core repository by this line:
uses: owaspsamm/core/.github/workflows/reusable-yaml-process.yml@438ef84c34d08befb5cd413a3344d1e6e1f75e9e
with:
language: fr
branch: ${{inputs.branch}}
model_folder: ${{inputs.model_folder}}
This is calling
"owaspsamm" project,
"core" repository,
".github/workflows/reusable-yaml-process.yml" -- the shared workflow file
"438ef84c34d08befb5cd413a3344d1e6e1f75e9e" -- this is the commit hash of the file that is going to be used. If we update the "reusable-yaml-process.yml" file we must also update this commit hash in the language repository workflow file, otherwise an old version of the shared workflow will be used.
We are also passing the parameters that are entered when triggering the language repository workflow and another "language" parameter with the value "fr". This third parameter should be the language shortcode. Note that this parameter is going to be the URL prefix when the website is deployed (e.g. /fr/model/design)
After the Github Action is finished successfully the resulting files will be pushed on "markdown" branch in the language repository. Later when the website is deploying it will use those files.
The core model repository should contain the reusable workflow file that the language repositories are going to use to convert YAML files to markdown.
# File is reusable-yaml-process.yml
name: Reusable workflow example
on:
workflow_call:
inputs:
language:
required: true
type: string
branch:
required: true
type: string
model_folder:
required: true
type: string
jobs:
generate-markdown:
runs-on: ubuntu-latest
steps:
- name: 'Checkout using release is workflow dispatched'
uses: actions/checkout@v3
with:
ref: ${{ inputs.branch }}
- name: 'Create output dir and copy files to override spaces in directories'
run: |
mkdir output
- name: 'Generate model for website'
uses: docker://backnot/owasp-samm-process-yaml-content:latest
with:
args: '-d ${{ inputs.model_folder }} -o output -l ${{ inputs.language }}'
- name: 'Move generated files to common directory structure'
run: |
mkdir -p build/business-function/practice/stream
BASE=output/markdown
cp "$BASE"/{Design.md,Governance.md,Implementation.md,Operations.md,Verification.md} build/business-function
cp "$BASE"/*-??-?.md build/business-function/practice/stream
cp "$BASE"/*-??.md build/business-function/practice
- name: Deploy
uses: s0/git-publish-subdir-action@develop
env:
REPO: self
BRANCH: markdown
FOLDER: build
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SQUASH_HISTORY: false
This file is going to accept three parameters -- language, model branch, model folder. It is going to use the process-yaml-content script (https://github.com/owaspsamm/process-yaml-content/ via Docker) that is used for converting the YAML files to markdown files.
This is the workflow that language repositories can call to clone the original model to new branches
name: Create new translation version branch
on:
workflow_call:
inputs:
source_branch:
required: true
type: string
source_folder:
required: true
type: string
new_branch_name:
required: true
type: string
jobs:
pull_and_create_branch:
runs-on: ubuntu-latest
steps:
- name: Checkout current repo
uses: actions/checkout@v3
- name: Set up Git with GitHub Actions bot identity
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Pull content from another repository
run: |
git clone --branch ${{ inputs.source_branch }} --single-branch https://github.com/owaspsamm/core temp-repo
rm -rf temp-repo/.git
rsync -a --exclude='.git' temp-repo/ .
- name: Create a new branch with the pulled content
run: |
git checkout -b ${{ inputs.new_branch_name }}
git add ${{ inputs.source_folder }}
git commit -m "Pulled content from ${{ inputs.source_repo }}:${{ inputs.source_branch }}"
git push origin ${{ inputs.new_branch_name }}
The website is using Hugo framework (https://gohugo.io/). In order for Hugo to recognize several languages there are two ways. The way it works now is that each language model files are in different folder (e.g. fr/es/). And the other layout files are just with different ending of names (e.g. model.md, model.fr.md, model.es.md - English, French, Spanish contents of the file model.md)
It is all happening in the Github Actions workflow file. In the file there are 2 jobs. "updateHugoMod" and "deploy".
This workflow can be triggered in three ways.
1. By pushing tag to core repository (it will signal to website repository by repository dispatch event)
2. By pushing to main branch
3. Manually from the "Github Actions" tab
The main difference between the three is that if it is triggered as in step 1 it will sync English model files from core repository new release branch tag.
In "updateHugoMod" job the process is going to download the model files from the different places - core repository for the English files and the language repositories for the others. Note the bold lines below - we are passing repository and branch to the job.
...
- name: Get new release and commit to main
if: github.event_name == 'repository_dispatch'
env:
RELEASE: "v${{ steps.semver_parser.outputs.fullversion }}"
run: |
echo "We got a new SAMM release: v${{ steps.semver_parser.outputs.fullversion }}${RELEASE}"
hugo mod get "github.com/owaspsamm/core@markdown/${RELEASE}"
cat go.mod
- name: Get translations
run: |
hugo mod get "github.com/owaspsamm/i18n-FR@markdown"
hugo mod get "github.com/owaspsamm/i18n-ES@markdown"
...
In the website config/_default/config.toml file there is code that is importing/mounting the modules and telling the framework where each language files are located.
…...
[[module.imports]]
# content
path = "github.com/owaspsamm/core"
disabled = false
[[module.imports.mounts]]
source = "business-function"
target = "content/business-function"
lang = "en"
[[module.imports]]
# content
path = "github.com/owaspsamm/i18n-FR"
disabled = false
[[module.imports.mounts]]
source = "business-function"
target = "content/business-function"
lang = "fr"
[[module.imports]]
# content
path = "github.com/owaspsamm/i18n-ES"
disabled = false
[[module.imports.mounts]]
source = "business-function"
target = "content/business-function"
lang = "es"
…...
languageCode = "en-us"
# Site language. Available translations in the theme's `/i18n` directory.
defaultContentLanguage = "en"
[languages]
[languages.en]
languageName = "English"
weight = 1
contentDir = "content/en"
[languages.es]
languageName = "Español"
weight = 2
contentDir = "content/es"
[languages.fr]
languageName = "French"
weight = 3
contentDir = "content/fr"
In the folder i18n there are yaml files with all the languages and some translated strings.
In layouts/shortcodes/language-dropdown.html this file will be used in the dropdown with all the available languages (shown at the model table).
-
Create new language repository
-
Add this as Github Actions workflow file inside the repository
name: Generate web markdown
# Controls when the workflow will run
on:
workflow_dispatch:
inputs:
branch:
description: 'Enter branch to use YAML files from'
required: true
type: string
model_folder:
description: 'Enter folder to use YAML files from'
required: true
type: string
jobs:
shared-workflow-name:
uses: owaspsamm/core/.github/workflows/reusable-yaml-process.yml@438ef84c34d08befb5cd413a3344d1e6e1f75e9e
with:
language: fr
branch: ${{inputs.branch}}
model_folder: ${{inputs.model_folder}}
- Replace the hash after reusable-yaml-process.yml@ with the correct one (see it from core repository last commit of the file)
- Add the language to the website config file (config/_default/config.toml)
[[module.imports]]
# content
path = "github.com/owaspsamm/i18n-FR"
disabled = false
[[module.imports.mounts]]
source = "business-function"
target = "content/business-function"
lang = "fr"
….
[languages]
[languages.en]
languageName = "English"
weight = 1
contentDir = "content/en"
[languages.es]
languageName = "Español"
weight = 2
contentDir = "content/es"
[languages.fr]
languageName = "French"
weight = 3
contentDir = "content/fr"
- Add the language repository to the Github Actions workflow YML file inside "updateHugoMod" "Get translations" step
- name: Get translations
run: |
hugo mod get "github.com/owaspsamm/i18n-FR@markdown"
- Add new file to i18n folder of the website
- If you want to just don't show the language in the website language dropdown you can remove the file for the corresponding language from i18n folder.
- If you want full removal of the language from the website, reverse all the steps made to website repository from the above question
- Also the corresponding repository should be removed from go.mod file of the website main branch
-
Create branch named "markdown" in the language repository
-
Assuming that you have the required Github Action workflow file in the language repository (as specified in the above question regarding adding new language) you can trigger it from the Github Actions tab.