diff --git a/.gitlab/ci/docs.gitlab-ci.yml b/.gitlab/ci/docs.gitlab-ci.yml index 312c57aba586c76058f8e5ff926d370570503d07..3003370e842b05e6356ef8ce49668db32e6bbd1e 100644 --- a/.gitlab/ci/docs.gitlab-ci.yml +++ b/.gitlab/ci/docs.gitlab-ci.yml @@ -196,6 +196,24 @@ docs-i18n-lint markdown: - install_gitlab_gem - scripts/i18n_lint_doc.sh +# Japanese-specific Vale linting with language-specific rules +docs-i18n-lint japanese-vale: + extends: + - .default-retry + - .docs:rules:docs-i18n-lint-japanese + - .docs-markdown-lint-image + stage: lint + needs: [] + variables: + LANGUAGE_CODE: "ja-jp" + LANGUAGE_NAME: "Japanese" + VALE_FILTER: "locale_rules" + VALE_MIN_ALERT_LEVEL: "warning" + script: + - source ./scripts/utils.sh + - install_gitlab_gem + - scripts/i18n_lint_language_vale.sh + # Verify localized documentation files have corresponding English versions docs-i18n-lint paths: extends: diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml index b13fa9391a41b0de3890a82404ddfec653380401..49436c87d0990979b7859f58624fb50029e1d4f6 100644 --- a/.gitlab/ci/rules.gitlab-ci.yml +++ b/.gitlab/ci/rules.gitlab-ci.yml @@ -351,11 +351,17 @@ - "tooling/eslint-config/eslint-local-rules/**/*" .docs-i18n-patterns: &docs-i18n-patterns + - ".gitlab/ci/docs.gitlab-ci.yml" - "doc-locale/**/*" - "doc-locale/.markdownlint/.markdownlint-cli2.yaml" - "scripts/i18n_lint_doc.sh" - "scripts/i18n_verify_paths.sh" +.docs-ja-jp-patterns: &docs-ja-jp-patterns + - ".gitlab/ci/docs.gitlab-ci.yml" + - "scripts/i18n_lint_language_vale.sh" + - "doc-locale/ja-jp/**/*" + .if-tech-docs-localization: &if-tech-docs-localization if: '($CI_PROJECT_PATH == "gitlab-com/localization" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH) || ($CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_EVENT_TYPE != "merge_train") || @@ -1311,6 +1317,11 @@ - <<: *if-tech-docs-localization changes: *docs-i18n-patterns +.docs:rules:docs-i18n-lint-japanese: + rules: + - <<: *if-tech-docs-localization + changes: *docs-ja-jp-patterns + .docs:rules:deprecations-and-removals: rules: - <<: *if-default-refs diff --git a/doc-locale/ja-jp/.vale.ini b/doc-locale/ja-jp/.vale.ini new file mode 100644 index 0000000000000000000000000000000000000000..2e46c325ecd392d1dfb860235d052ebf57fb4f3e --- /dev/null +++ b/doc-locale/ja-jp/.vale.ini @@ -0,0 +1,14 @@ +# Vale configuration file for localized documentation. +# +# For more information, see https://vale.sh/docs/vale-ini. + +StylesPath = .vale +MinAlertLevel = suggestion + +IgnoredScopes = code, text.frontmatter.redirect_to + +[*.md] +BasedOnStyles = locale_rules + +# Ignore SVG markup +TokenIgnores = (\*\*\{\w*\}\*\*) diff --git a/doc-locale/ja-jp/.vale/locale_rules/ReferenceQuotationRemoval.yml b/doc-locale/ja-jp/.vale/locale_rules/ReferenceQuotationRemoval.yml new file mode 100644 index 0000000000000000000000000000000000000000..7e992b40d5ddaffaf1e00622a78a2cd013d231db --- /dev/null +++ b/doc-locale/ja-jp/.vale/locale_rules/ReferenceQuotationRemoval.yml @@ -0,0 +1,11 @@ +--- +name: locale_rules.ReferenceQuotationRemoval +description: | + Remove quotation marks around reference links +extends: existence +message: "Check for quotation marks around reference links at '%s'" +level: warning +nonword: true +scope: raw +tokens: + - '「\[.+?\]\([^)]+\)」' diff --git a/doc-locale/ja-jp/.vale/vale.tmpl b/doc-locale/ja-jp/.vale/vale.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..3fe958023b9f28871c10c8a6a0a7f6947dcb4dea --- /dev/null +++ b/doc-locale/ja-jp/.vale/vale.tmpl @@ -0,0 +1,48 @@ +{{- /* Modify Vale's output https://docs.errata.ai/vale/cli#--output */ -}} + +{{- /* Keep track of our various counts */ -}} + +{{- $e := 0 -}} +{{- $w := 0 -}} +{{- $s := 0 -}} + +{{- /* Range over the linted files */ -}} + +{{- range .Files}} +{{- $path := .Path | underline -}} + +{{- /* Range over the file's alerts */ -}} + +{{- range .Alerts -}} + +{{- $error := "" -}} +{{- if eq .Severity "error" -}} + {{- $error = .Severity | red -}} + {{- $e = add1 $e -}} +{{- else if eq .Severity "warning" -}} + {{- $error = .Severity | yellow -}} + {{- $w = add1 $w -}} +{{- else -}} + {{- $error = .Severity | blue -}} + {{- $s = add1 $s -}} +{{- end}} + +{{- /* Variables setup */ -}} + +{{- $path = $path -}} +{{- $loc := printf "Line %d, position %d" .Line (index .Span 0) -}} +{{- $check := printf "%s" .Check -}} +{{- $message := printf "%s" .Message -}} +{{- $link := printf "%s" .Link -}} + +{{- /* Output */ -}} + +{{ $path }}: + {{ $loc }} (rule {{ $check }}) + {{ $error }}: {{ $message }} + More information: {{ $link }} + +{{end -}} +{{end -}} + +{{- $e}} {{"errors" | red}}, {{$w}} {{"warnings" | yellow}}, and {{$s}} {{"suggestions" | blue}} found in {{.LintedTotal}} {{.LintedTotal | int | plural "file" "files"}}. diff --git a/doc/development/documentation/testing/_index.md b/doc/development/documentation/testing/_index.md index 2cfc017a749f0d15c25e37ab978e76fb8d931aca..809dba457177d8d3098f8b1729100bd07537d88c 100644 --- a/doc/development/documentation/testing/_index.md +++ b/doc/development/documentation/testing/_index.md @@ -94,15 +94,94 @@ To ensure quality across all our translated content, we've implemented testing f multiple languages. These tests mirror those used for the English version, but run on internationalized content in the `/doc-locale/` or `/docs-locale/` directories. +### General translation linting + +The `docs-i18n-lint markdown` job runs general linting tests on all translated documentation: + +- **markdownlint**: Checks Markdown structure and formatting +- **Vale**: Runs general documentation style rules using the `gitlab_docs` filter + +This job runs when any files in `/doc-locale/` or `/docs-locale/` are modified and provides baseline quality checks +for all translated content. + | Project | English Dir | Translation Dir | Linting Jobs | | ----- | ----- | ----- | ----- | -| GitLab | [`/doc`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/doc) | [`/doc-locale`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/doc-locale) | `docs-i18n-lint markdown` | +| GitLab | [`/doc`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/doc) | [`/doc-locale`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/doc-locale) | `docs-i18n-lint markdown`
`docs-i18n-lint japanese-vale` | | GitLab Runner | [`/docs`](https://gitlab.com/gitlab-org/gitlab-runner/-/tree/main/docs) | [`/docs-locale`](https://gitlab.com/gitlab-org/gitlab-runner/-/tree/main/docs-locale?ref_type=heads) | `docs:lint i18n markdown` | | Linux package | [`/doc`](https://gitlab.com/gitlab-org/omnibus-gitlab/-/tree/master/doc) | [`/doc-locale`](https://gitlab.com/gitlab-org/omnibus-gitlab/-/tree/master/doc-locale) | `docs-lint-i18n markdown`
`docs-lint-i18n content` | | Charts | [`/doc`](https://gitlab.com/gitlab-org/charts/gitlab/-/tree/master/doc) | [`/doc-locale`](https://gitlab.com/gitlab-org/charts/gitlab/-/tree/master/doc-locale) | `check_docs_i18n_content`
`check_docs_i18n_markdown` | | Operator | [`/doc`](https://gitlab.com/gitlab-org/cloud-native/gitlab-operator/-/tree/master/doc) | [`/doc-locale`](https://gitlab.com/gitlab-org/cloud-native/gitlab-operator/-/tree/master/doc-locale) | `docs-i18n-lint content`
`docs-i18n-lint markdown` | -### Path verification of orphaned translation Files +### Language-specific translation linting + +For languages with specific style requirements, we provide dedicated CI/CD jobs that run +language-specific Vale rules. Each language has its own job that only runs when files +in that language are modified. + +#### Japanese language support + +The `docs-i18n-lint japanese-vale` job runs Japanese-specific Vale linting: + +- Script: [`scripts/i18n_lint_language_vale.sh`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/scripts/i18n_lint_language_vale.sh) +- Configuration: `doc-locale/ja-jp/.vale.ini` +- Vale filter: `locale_rules` +- Triggers: Only runs when these files change: + - `doc-locale/ja-jp/**/*.md` - Japanese documentation files + - `doc-locale/ja-jp/.vale.ini` - Japanese Vale configuration + - `scripts/i18n_lint_language_vale.sh` - Universal language linting script + +The job uses environment variables to configure the universal script: + +```yaml +variables: + LANGUAGE_CODE: "ja-jp" + LANGUAGE_NAME: "Japanese" + VALE_FILTER: "locale_rules" + VALE_MIN_ALERT_LEVEL: "warning" +``` + +#### Adding new languages + +To add language-specific linting for additional languages: + +- Create language-specific Vale configuration at `doc-locale/LANGUAGE_CODE/.vale.ini` +- Add a new CI job in `.gitlab/ci/docs.gitlab-ci.yml`: + + ```yaml + docs-i18n-lint LANGUAGE-vale: + extends: + - .default-retry + - .docs:rules:docs-i18n-lint-LANGUAGE + - .docs-markdown-lint-image + stage: lint + needs: [] + variables: + LANGUAGE_CODE: "LANGUAGE_CODE" # e.g., "fr-fr", "de-de" + LANGUAGE_NAME: "LANGUAGE_NAME" # e.g., "French", "German" + VALE_FILTER: "VALE_FILTER_NAME" # e.g., "french_rules" + VALE_MIN_ALERT_LEVEL: "warning" # or "error" for stricter rules + script: + - source ./scripts/utils.sh + - install_gitlab_gem + - scripts/i18n_lint_language_vale.sh + ``` + +- Add triggering rules in `.gitlab/ci/rules.gitlab-ci.yml`: + + ```yaml + .docs:rules:docs-i18n-lint-LANGUAGE: + rules: + - <<: *if-tech-docs-localization + changes: + - "doc-locale/LANGUAGE_CODE/**/*.md" + - "doc-locale/LANGUAGE_CODE/.vale.ini" + - "scripts/i18n_lint_language_vale.sh" + ``` + +The universal script approach eliminates code duplication while maintaining language-specific +customization through environment variables. + +### Path verification of orphaned translation files The `docs-i18n-lint paths` job fails if translated files in `/doc-locale` have no corresponding English source files. The job runs when: diff --git a/scripts/i18n_lint_language_vale.sh b/scripts/i18n_lint_language_vale.sh new file mode 100755 index 0000000000000000000000000000000000000000..27d7658f230b14dc05225e068a86bd483448c747 --- /dev/null +++ b/scripts/i18n_lint_language_vale.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# Universal language-specific Vale linting script +# Uses environment variables to configure language-specific behavior + +set -euo pipefail + +COLOR_RED="\e[31m" +COLOR_GREEN="\e[32m" +COLOR_RESET="\e[39m" + +# Optional environment variables with defaults +VALE_FILTER="${VALE_FILTER:-locale_rules}" +VALE_MIN_ALERT_LEVEL="${VALE_MIN_ALERT_LEVEL:-warning}" + +cd "$(dirname "$0")/.." || exit 1 +printf "INFO: Running ${LANGUAGE_NAME}-specific Vale linting at path $(pwd)...\n" +printf "INFO: Language Code: ${LANGUAGE_CODE}\n" +printf "INFO: Vale Filter: ${VALE_FILTER}\n" +printf "INFO: Min Alert Level: ${VALE_MIN_ALERT_LEVEL}\n" + +ERRORCODE=0 + +# shellcheck disable=SC2059 +printf "${COLOR_GREEN}INFO: Running ${LANGUAGE_NAME}-specific Vale rules...${COLOR_RESET}\n" + +# Run vale with either specified files or default path +if [ $# -gt 0 ]; then + vale --config="doc-locale/${LANGUAGE_CODE}/.vale.ini" --minAlertLevel "${VALE_MIN_ALERT_LEVEL}" "$@" || { + printf "${COLOR_RED}ERROR: ${LANGUAGE_NAME} Vale rules found issues in translation files${COLOR_RESET}\n" + ((ERRORCODE++)) + } +else + vale --config="doc-locale/${LANGUAGE_CODE}/.vale.ini" --minAlertLevel "${VALE_MIN_ALERT_LEVEL}" "doc-locale/${LANGUAGE_CODE}/" || { + printf "${COLOR_RED}ERROR: ${LANGUAGE_NAME} Vale rules found issues in translation files${COLOR_RESET}\n" + ((ERRORCODE++)) + } +fi + +# Report results +if [ "$ERRORCODE" -ne 0 ]; then + printf "\n${COLOR_RED}ERROR: ${LANGUAGE_NAME} Vale lint checks failed!${COLOR_RESET}\n" + exit 1 +else + printf "\n${COLOR_GREEN}SUCCESS: All ${LANGUAGE_NAME} Vale lint checks passed${COLOR_RESET}\n" + exit 0 +fi diff --git a/spec/dot_gitlab_ci/rules_spec.rb b/spec/dot_gitlab_ci/rules_spec.rb index 76a8a6a742431a70e45449c6db660f391dff7c16..14844d5cbc2d128017da0ba9f89008fa63117586 100644 --- a/spec/dot_gitlab_ci/rules_spec.rb +++ b/spec/dot_gitlab_ci/rules_spec.rb @@ -205,6 +205,7 @@ Dir.glob('*.md') + Dir.glob('changelogs/*') + Dir.glob('doc/.{markdownlint,vale}/**/*', File::FNM_DOTMATCH) + + Dir.glob('doc-locale/**/*', File::FNM_DOTMATCH) + Dir.glob('node_modules/**/*', File::FNM_DOTMATCH) + Dir.glob('patches/*') + Dir.glob('public/assets/**/.*') +