Skip to content

feat: Refactor localization to YAML catalogs with runtime language overrides#6506

Open
Copilot wants to merge 1 commit into
mainfrom
copilot/add-multilanguage-support
Open

feat: Refactor localization to YAML catalogs with runtime language overrides#6506
Copilot wants to merge 1 commit into
mainfrom
copilot/add-multilanguage-support

Conversation

Copilot AI commented May 23, 2026

Copy link
Copy Markdown
Contributor
  • Inspect failing lint workflow run and fetch failing job logs
  • Identify exact lint error and impacted file/line
  • Reproduce lint failure locally using golangci-lint v2.7.2
  • Apply minimal code fix for lint error (interface{} -> any)
  • Re-run local lint to confirm pass (0 issues)
  • Run targeted tests for changed package (go test ./server/core/config/...)
  • Run formatting check (make check-fmt)
  • Run validation checks
  • Address validation feedback: improve decodeYAML doc clarity for yaml.v3 merge-key panic handling
  • Address validation feedback: strengthen Spanish plan rendering test with plan-specific assertion and plan-success result
  • Re-run lint/tests locally (golangci-lint run, go test ./server/core/config/... ./server/events/...)
  • Re-run validation checks and report results

@nitrocode nitrocode changed the title Refactor localization to YAML catalogs with runtime language overrides feat: Refactor localization to YAML catalogs with runtime language overrides May 23, 2026
@nitrocode nitrocode marked this pull request as ready for review May 23, 2026 21:01
Copilot AI review requested due to automatic review settings May 23, 2026 21:01
@dosubot dosubot Bot added docs Documentation feature New functionality/enhancement go Pull requests that update Go code labels May 23, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors Atlantis comment localization from hardcoded strings to embedded YAML catalogs, and adds support for operator-provided runtime language overrides via a custom YAML catalog file (without rebuilding the binary).

Changes:

  • Added server/i18n package with embedded YAML catalogs (en, es) plus merge/override behavior for custom catalogs.
  • Wired language selection and custom catalog path through CLI flags/config into events.MarkdownRenderer.
  • Added Spanish template overrides under server/events/templates/i18n/es/ and expanded unit tests + docs for the new config options.

Reviewed changes

Copilot reviewed 23 out of 23 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
server/user_config.go Adds language and language-config-file to server user config.
server/server.go Wires i18n.TranslatorConfig into markdown renderer construction.
server/i18n/locales/en.yaml Adds built-in English YAML catalog.
server/i18n/locales/es.yaml Adds built-in Spanish YAML catalog.
server/i18n/i18n.go Implements catalog parsing, merging, language normalization/validation, and translator.
server/i18n/i18n_test.go Adds unit tests for normalization, validation, built-in loading, and custom override behavior.
server/events/templates/i18n/es/wrapped_err.tmpl Spanish override for wrapped error rendering.
server/events/templates/i18n/es/unwrapped_err.tmpl Spanish override for unwrapped error rendering.
server/events/templates/i18n/es/single_project_plan_unsuccessful.tmpl Spanish override for single-project unsuccessful plan template.
server/events/templates/i18n/es/single_project_plan_success.tmpl Spanish override for single-project successful plan template (with instructions).
server/events/templates/i18n/es/single_project_apply.tmpl Spanish override for single-project apply template.
server/events/templates/i18n/es/multi_project_plan.tmpl Spanish override for multi-project plan template.
server/events/templates/i18n/es/multi_project_plan_footer.tmpl Spanish override for plan footer summary/instructions.
server/events/templates/i18n/es/multi_project_header.tmpl Spanish override for multi-project header template.
server/events/templates/i18n/es/multi_project_apply.tmpl Spanish override for multi-project apply template.
server/events/templates/i18n/es/multi_project_apply_footer.tmpl Spanish override for apply footer summary.
server/events/templates/i18n/es/log.tmpl Spanish override for verbose log template.
server/events/templates/i18n/es/failure.tmpl Spanish override for failure template.
server/events/markdown_renderer.go Loads localized template sets; uses translator for command/vcs labels; introduces config-based localization.
server/events/markdown_renderer_test.go Adds tests for Spanish localization and custom catalog overrides.
runatlantis.io/docs/server-configuration.md Documents --language and --language-config-file with schema and behavior.
cmd/server.go Adds flags/env wiring, defaults, and validation for language + custom catalog.
cmd/server_test.go Adds validation coverage for language selection and custom catalog errors.
Comments suppressed due to low confidence (1)

server/events/markdown_renderer.go:281

  • policyCheckResultsWrapped/policyCheckResultsUnwrapped templates gate some content behind if eq .Command "Policy Check". With localization/custom command titles, common.Command is no longer guaranteed to be "Policy Check", so those sections will be skipped for policy_check results. Consider passing a stable (non-localized) command title into the policyCheckResultsData used for these templates so the condition remains correct regardless of localization.
		} else if result.PolicyCheckResults != nil && matchesCommandTitle(common.Command, policyCheckCommandTitle, m.translator) {
			policyCheckResults := policyCheckResultsData{
				PreConftestOutput:     result.PolicyCheckResults.PreConftestOutput,
				PostConftestOutput:    result.PolicyCheckResults.PostConftestOutput,
				PolicyCheckResults:    *result.PolicyCheckResults,

Comment thread server/events/markdown_renderer.go Outdated
Comment thread server/events/templates/i18n/es/log.tmpl
@jamengual

jamengual commented May 25, 2026

Copy link
Copy Markdown
Contributor

Code Review

Reviewed +996/-51 across 30 files. Two distinct changes bundled: localization framework + unrelated yaml.v3 merge-key panic fix.

Strengths

  • Stable identifier fix. Decoupling common.Command (display) from common.CommandName (routing key) fixes real bug where translated titles broke template selection. TestRenderUsesStableCommandIdentifierWhenTitlesCollide validates this.
  • Test coverage solid: Spanish render, custom override, colliding titles, policy check rendering, YAML panic regression.
  • AGENTS.md updated with lesson learned — self-documenting.
  • YAML panic fix: recover() wrapper minimal, scoped to user YAML decode. Fuzz seed committed.

Issues

HIGH — Bundled unrelated changes. PR mixes localization feature (~950 lines) with yaml.v3 merge-key panic fix (~70 lines + fuzz). Should be 2 PRs. Reviewers and git bisect suffer. PR body reads as a lint-fix task list; doesn't describe feature scope.

MEDIUM — Variadic config is non-idiomatic.

func NewMarkdownRenderer(..., localizationConfigs ...i18n.TranslatorConfig) *MarkdownRenderer

Variadic for an optional single value is an anti-pattern; only first element used, extras silently ignored. Prefer *i18n.TranslatorConfig (nil = default), a functional-option pattern, or a separate constructor.

MEDIUM — MustNewTranslator misleading + silently swallows errors.

func MustNewTranslator(config TranslatorConfig) *Translator {
    translator, err := NewTranslator(config)
    if err == nil { return translator }
    translator, _ = NewTranslator(TranslatorConfig{LanguageCode: DefaultLanguage})
    if translator != nil { return translator }
    return &Translator{...}
}

Name suggests panic on failure; it never panics. Rename NewTranslatorOrDefault. Triple fallback masks config errors with no log — since cmd/server.go validates upfront, this is "unreachable", but if reached operator sees no signal. Add logger.Warn on fallback.

MEDIUM — Custom catalog YAML not protected from same panic.
parseCatalog in server/i18n/i18n.go calls yaml.Unmarshal directly. Same merge-key panic class affects operator-supplied --language-config-file. Recommend route parseCatalog through a recover() wrapper (or reuse decodeYAML-style helper) for symmetry. Otherwise a malformed custom catalog crashes startup.

LOW — decodeYAML error strips stack.

retErr = fmt.Errorf("yaml: unexpected error while parsing: %v", r)

For an upstream library bug, debugging benefits from stack. Consider attaching debug.Stack() at DEBUG log level before converting to error.

LOW — Embed glob fragility.

//go:embed templates/*.tmpl templates/i18n/*/*.tmpl

New locale directory with typo (e.g. zh-CN) silently falls back to English. Consider asserting locale subdirs match supportedLanguages at init.

LOW — Spanish strings need native review.

  • "Pull Request" → "Solicitud de extracción": technically correct but Spanish devs typically leave untranslated.
  • "Policy Check" → "Verificar políticas": verb form inconsistent with noun titles ("Aplicar", "Planificar").

Security / Performance

No security concerns. Catalog path is operator-supplied via CLI flag, not user input — no traversal risk. Translator built once at startup; map lookups O(1). Negligible runtime cost.

Recommendations

  1. Split PR: localization vs YAML panic fix.
  2. Drop variadic TranslatorConfig; use pointer or options.
  3. Rename MustNewTranslatorNewTranslatorOrDefault and log fallback.
  4. Apply recover() wrapper to parseCatalog for custom catalog symmetry.
  5. Rewrite PR body to describe feature scope.
  6. Native Spanish review of PR/MR labels and policy_check title.

@GMartinez-Sisti

GMartinez-Sisti commented May 27, 2026

Copy link
Copy Markdown
Member

Regarding the approach, supporting the same templates for different languages seems like it's going to be a hassle to manage and error prone. A common approach is to only manage the localization strings in a single file per language and the templating would be similar for all. What do you think of this logic?

@chenrui333 chenrui333 force-pushed the copilot/add-multilanguage-support branch 3 times, most recently from 7c88eff to cc0b267 Compare June 26, 2026 20:52
…errides

Add configurable Atlantis pull request comment localization with built-in English and Spanish catalogs plus optional custom YAML catalog overrides.

Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com>
Signed-off-by: Rui Chen <rui@chenrui.dev>
@chenrui333 chenrui333 force-pushed the copilot/add-multilanguage-support branch from cc0b267 to 2a268e6 Compare June 26, 2026 22:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Documentation feature New functionality/enhancement go Pull requests that update Go code size/l

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants