Author: Bruno Borges
Original post on Foojay: Read More
Table of Contents
The Arabic Surprise: RTL Support
How I used Claude Sonnet 4.6 and fleets of GitHub Copilot Coding Agents to internationalize java.evolved — from spec to deployment
java.evolved is a static site I built to showcase modern Java patterns side-by-side with their legacy equivalents. 112 patterns across 11 categories — language, collections, streams, concurrency, and more — each with code comparisons, explanations, and curated documentation links. All generated from YAML content files by a JBang-powered Java build script.
By the end of February 25, the entire site was English-only. By the morning of February 26, it was available in 9 languages — English, German, Spanish, Portuguese (Brazil), Simplified Chinese, Arabic, French, Japanese, and Korean — with full RTL support for Arabic. The total human effort was a few hours of prompting, reviewing PRs, and filing one bug.
This is the story of that experiment.
The Architecture Decision: Let the AI Draft the Spec
The first step wasn’t writing code. It was writing a specification.
I opened issue #74 — “Plan architectural change for i18n” — and assigned it to a Copilot Coding Agent. The prompt was simple: propose an architectural plan for internationalizing the website, considering the existing static-site structure.
The agent (PR #75) came back with a comprehensive i18n specification that addressed:
- Two-layer translation model: UI strings (labels, nav, footer) separated from content translations (pattern titles, explanations, summaries)
- Partial translation files: Translation files contain only translatable fields. Structural data (code snippets, navigation links, metadata) always comes from the English source of truth
- Graceful fallback: Missing translations fall back to English with a build-time warning — no page is ever blank
- Locale registry: A simple
locales.propertiesfile drives the entire build pipeline and language selector - AI-friendly design: The architecture was explicitly designed so that an AI receives the full English content and returns a partial translation file — no field-filtering logic needed in the prompt
This last point proved prescient. The clean separation between “what changes per locale” and “what stays constant” meant each translation task was self-contained and parallelizable.
After iterating through review comments over 5 days (the original PR had 12 comments of back-and-forth), the spec was merged on February 25.
Phase 1: Building the Infrastructure
With the spec in hand, I coordinated an agent locally with Coilot CLI to implement the core i18n infrastructure in PR #83 — the generator changes that made everything locale-aware:
- The
generate.javabuild script learned to iterate all locales fromlocales.properties - Template tokens like
{{sections.codeComparison}}replaced hard-coded English strings hreflangmeta tags, a locale picker dropdown, and client-side locale detection were added- The
resolveSnippetfunction loads translated content overlaid onto the English base, falling back gracefully when a translation doesn’t exist
This was the only PR that required significant intervention. Everything after it was delegation.
Phase 2: The First Translations (Spanish + Portuguese)
The first real translation — Spanish — came in PR #84. This PR also migrated the English content files from JSON to YAML for improved readability — a format change that the AI handled naturally since the generator already supported multiple formats.
Brazilian Portuguese followed immediately in PR #85, completing all 112 pattern files (going from 3/112 translated to 112/112 — 100% coverage). These first two translations validated the architecture and surfaced a CI issue: the deploy workflow’s path triggers didn’t match YAML files or the translations/ directory. A quick fix in PR #86 resolved that.
Phase 3: The Fleet — 6 Languages in Parallel
This is where things got interesting. With the architecture proven and two complete translations validated, I launched a fleet of Copilot Coding Agents — multiple agents working in parallel, each assigned a single language. I used the Copilot CLI /delegate command to dispatch them asynchonously, all with the same prompt:
| PR | Language | Agent | Time to PR |
|---|---|---|---|
| #87 | Japanese (日本語) | Copilot | ~36 min |
| #88 | German (Deutsch) | Copilot | ~35 min |
| #89 | French (Français) | Copilot | ~32 min |
| #90 | Chinese 中文 (简体) | Copilot | ~58 min |
| #91 | Arabic (العربية) | Copilot | ~53 min |
| #94 | Korean (한국어) | Copilot | ~24 min |
Each agent independently:
- Read the i18n spec and understood the file structure
- Created a UI strings YAML file (
translations/strings/{locale}.yaml) with 60+ translated keys - Generated 112 content translation YAML files — one per pattern, across all 11 categories
- Registered the locale in
locales.properties - Opened a PR with a detailed description of what was translated
All six PRs were opened within a span of about 12 minutes (2:33 AM to 2:45 AM) and were all merged within the next hour. No translation conflicts, no merge issues, no structural errors. The partial-file architecture did exactly what it was designed to do — each agent’s output was isolated to its own locale directory.
The Numbers
By the time the fleet finished:
- 8 locales fully supported (besides English)
- 112 patterns × 8 translated locales = 896 content translation files
- 8 UI string files with 60+ keys each
- ~1,008 generated HTML pages (112 pages × 8 locales)
- 8 localized search indexes (
snippets.jsonper locale)
The Arabic Surprise: RTL Support
The most impressive moment was the Arabic translation (PR #91). The agent not only translated, it also noted that Arabic is a right-to-left language and proactively added RTL infrastructure:
- Added
dir="{{htmlDir}}"to the “ tag in both templates - Modified the generator to resolve
htmlDirto"rtl"for Arabic and"ltr"for all other locales - Updated the Python benchmark generator to pass the new token
This was a genuinely thoughtful architectural change that I hadn’t explicitly requested. The agent understood that Arabic support implies RTL layout and acted on it.

The One Bug
Of course, it wasn’t perfect. When dir="rtl" is applied globally, the browser flips everything — including Java source code blocks and the navigation bar, which IMO should always be LTR regardless of locale. I spotted this when reviewing the deployed site and filed issue #96.
A Copilot Coding Agent fixed it in PR #97 within minutes, adding targeted CSS overrides:
[dir="rtl"] nav,
[dir="rtl"] .nav-inner {
direction: ltr;
}
[dir="rtl"] pre,
[dir="rtl"] code,
[dir="rtl"] .code-text,
[dir="rtl"] .card-code,
[dir="rtl"] .compare-code {
direction: ltr;
text-align: left;
unicode-bidi: embed;
}
Arabic prose continues to render RTL. Java code stays LTR. One bug, one issue, one PR, fixed in minutes. That’s the entire human intervention required for 8-language support.
Why It Worked: Architecture as Force Multiplier
This experiment succeeded because of deliberate architectural decisions, not just because of a magic AI prompt. A few design choices made parallelized AI translation almost trivially easy:
1. Source of Truth Separation
Content files contain both translatable text and structural data (code, navigation, metadata). But translation files contain only the translatable fields. The generator overlays translations onto the English base at build time. This means:
- AI agents can’t accidentally modify code snippets or break navigation
- Translation files are small and self-contained
- Structural changes to the English source propagate immediately without needing to update translations
2. Partial File Fallback
If a pattern has no translation file for a locale, the site shows the English content with an “untranslated” banner. This means:
- Partial translations are always valid
- New patterns added in English are immediately visible in all locales
- There’s no “all or nothing” pressure on translation completeness
3. Convention Over Configuration
Each locale follows the same directory structure. Adding a new language is a checklist:
- Add a line to
locales.properties - Create
translations/strings/{locale}.yaml - Create files under
translations/content/{locale}/
No code changes needed in the generator. No template modifications. The AI spec anticipated this workflow, and the agents followed it exactly.
Lessons Learned
What Went Well
- Spec-first approach: Having the AI draft the specification before any implementation meant the architecture was explicitly designed for AI-driven translation from day one
- Fleet parallelism: Six language translations running simultaneously with zero conflicts demonstrates that well-isolated task boundaries enable effortless parallelization
- Proactive problem-solving: The Arabic agent identifying and implementing RTL support without being explicitly asked shows that LLMs can reason about the downstream implications of their translations
- Technical term preservation: Across all 9 languages, Java API names, annotations, JDK versions, and code examples were correctly left in English — the agents understood what should and shouldn’t be translated in a technical context
What Required Human Intervention
- One bug: The RTL global flip affecting code blocks. This is a classic CSS gotcha that even experienced developers might miss on first pass. Filed as an issue, fixed by an agent in minutes
- CI pipeline fixes: The deploy workflow needed path trigger updates after the JSON→YAML migration. A routine ops fix
- Review and merge: Each PR needed a human to review and merge. The content quality was consistently good, but spot-checking translations in languages you speak is still important
The Timeline
| Time (UTC) | Event |
|---|---|
| Feb 20, 20:33 | Issue #74 opened — “Plan architectural change for i18n” |
| Feb 20, 20:33 | PR #75 opened — i18n specification (by Copilot Agent) |
| Feb 25, 20:56 | PR #75 merged (after 5 days of procrastination, and other projects at hand… finally!) |
| Feb 25, 23:49 | PR #83 merged — core i18n infrastructure |
| Feb 26, 01:28 | PR #84 merged — Spanish translation + JSON→YAML migration |
| Feb 26, 02:27 | PR #85 merged — Complete Brazilian Portuguese (112/112) |
| Feb 26, 02:29 | PR #86 merged — CI path trigger fix |
| Feb 26, 02:33–02:45 | PRs #87–#91 opened — fleet of 6 language agents launched |
| Feb 26, 03:09–03:39 | All fleet PRs merged (Japanese, German, French, Chinese, Arabic) |
| Feb 26, 03:51 | PR #94 opened — Korean (final language) |
| Feb 26, 03:59 | Issue #96 filed — Arabic RTL bug |
| Feb 26, 04:12 | PR #97 merged — RTL fix |
| Feb 26, 04:15 | PR #94 merged — Korean complete |
From spec merge to 8-language site: ~7 hours. From fleet launch to all 6 languages merged: ~1 hour.
Conclusion
The experiment proved a simple thesis: if you design your architecture for AI-driven workflows, AI agents can do remarkable things.
I didn’t build a custom translation pipeline or prompt-engineering framework. I wrote a specification. An AI agent drafted it, I refined it through code review, and then a fleet of agents executed against it. The architecture — partial files, fallback behavior, source-of-truth separation — did all the heavy lifting.
The result is a Java patterns reference site available in 8 languages, with 1,008 generated pages, serving developers who speak English, German, Spanish, Portuguese, Chinese, Arabic, French, and Korean. It handles right-to-left layouts. It has localized search. Every page has proper hreflang tags for SEO.
And the only bug was a CSS rule that took 13 minutes from report to fix.
The future isn’t AI replacing developers. It’s developers designing systems that let AI do what it’s good at — repetitive, structured, parallelizable work — while humans focus on architecture, review, and the occasional RTL bug.
java.evolved is open source at github.com/javaevolved/javaevolved.github.io. The i18n specification lives at specs/i18n/i18n-spec.md.
The post Translating a Website into 8 Languages with AI Agents in One Night appeared first on foojay.
NLJUG – Nederlandse Java User Group NLJUG – de Nederlandse Java User Group – is opgericht in 2003. De NLJUG verenigt software ontwikkelaars, architecten, ICT managers, studenten, new media developers en haar businesspartners met algemene interesse in alle aspecten van Java Technology.