Skip to content

Commit fe248f0

Browse files
brunoborgesCopilot
andcommitted
Update i18n spec to reflect YAML UI strings implementation
- Change all UI string file references from .json to .yaml - Update en.yaml schema example to match current complete key set - Update locales.properties example to list all 9 supported locales Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 557e64e commit fe248f0

File tree

1 file changed

+127
-89
lines changed

1 file changed

+127
-89
lines changed

specs/i18n/i18n-spec.md

Lines changed: 127 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Internationalization is implemented via two distinct layers:
77

88
1. **UI strings layer** — every piece of hard-coded copy in the templates
99
(labels, button text, nav, footer, etc.) is extracted into a per-locale
10-
`translations/strings/{locale}.json` file and injected at build time.
10+
`translations/strings/{locale}.yaml` file and injected at build time.
1111

1212
2. **Content translation layer** — translated pattern JSON files are complete,
1313
stand-alone replacements stored under `translations/content/{locale}/`.
@@ -37,9 +37,9 @@ content/ # English content (source of truth)
3737
3838
translations/ # All i18n artifacts
3939
strings/
40-
en.json # English UI strings (extracted from templates)
41-
pt-BR.json # Partial — missing keys fall back to en.json
42-
ja.json
40+
en.yaml # English UI strings (extracted from templates)
41+
pt-BR.yaml # Partial — missing keys fall back to en.yaml
42+
ja.yaml
4343
content/
4444
pt-BR/
4545
language/
@@ -90,104 +90,142 @@ site/ # Generated output
9090
```properties
9191
# html-generators/locales.properties
9292
# format: locale=Display name (first entry is the default/primary locale)
93-
en=English
94-
pt-BR=Português (Brasil)
95-
ja=日本語
93+
en=🇬🇧 English
94+
de=🇩🇪 Deutsch
95+
es=🇪🇸 Español
96+
pt-BR=🇧🇷 Português (Brasil)
97+
zh-CN=🇨🇳 中文 (简体)
98+
ar=🇸🇦 العربية
99+
fr=🇫🇷 Français
100+
ja=🇯🇵 日本語
101+
ko=🇰🇷 한국어
96102
```
97103

98104
The generator reads this file to know which locales to build and what label
99105
to show in the language selector.
100106

101107
---
102108

103-
## `translations/strings/{locale}.json` Schema
109+
## `translations/strings/{locale}.yaml` Schema
104110

105111
Every user-visible string in the templates is assigned a dot-separated key.
106112
The English file is the complete reference; locale files are partial and only
107113
need to include keys that differ from English.
108114

109-
```json
110-
// translations/strings/en.json
111-
{
112-
"site": {
113-
"title": "java.evolved",
114-
"tagline": "Java has evolved. Your code can too.",
115-
"description": "A collection of modern Java code snippets. Every old Java pattern next to its clean, modern replacement — side by side."
116-
},
117-
"nav": {
118-
"allPatterns": "← All patterns",
119-
"toggleTheme": "Toggle theme",
120-
"viewOnGitHub": "View on GitHub"
121-
},
122-
"sections": {
123-
"codeComparison": "Code Comparison",
124-
"whyModernWins": "Why the modern way wins",
125-
"oldApproach": "Old Approach",
126-
"modernApproach": "Modern Approach",
127-
"sinceJdk": "Since JDK",
128-
"difficulty": "Difficulty",
129-
"jdkSupport": "JDK Support",
130-
"howItWorks": "How it works",
131-
"relatedDocs": "Related Documentation",
132-
"relatedPatterns": "Related patterns"
133-
},
134-
"filters": {
135-
"show": "Show:",
136-
"all": "All",
137-
"difficulty": {
138-
"beginner": "Beginner",
139-
"intermediate": "Intermediate",
140-
"advanced": "Advanced"
141-
}
142-
},
143-
"search": {
144-
"placeholder": "Search snippets…",
145-
"noResults": "No results found.",
146-
"esc": "ESC"
147-
},
148-
"copy": {
149-
"copy": "Copy",
150-
"copied": "Copied!"
151-
},
152-
"footer": {
153-
"madeWith": "Made with ❤️ by",
154-
"inspiredBy": "Inspired by",
155-
"viewOnGitHub": "View on GitHub"
156-
},
157-
"support": {
158-
"available": "Available",
159-
"preview": "Preview",
160-
"experimental": "Experimental"
161-
}
162-
}
115+
```yaml
116+
# translations/strings/en.yaml
117+
site:
118+
title: java.evolved
119+
tagline: Java has evolved. Your code can too.
120+
tagline_line1: Java has evolved.
121+
tagline_line2: Your code can too.
122+
description: A collection of modern Java code snippets. Every old Java pattern next
123+
to its clean, modern replacement — side by side.
124+
heroSnippetCount: '✦ {{snippetCount}} modern patterns · Java 8 → Java 25'
125+
heroOld: Old
126+
heroModern: Modern
127+
allComparisons: All comparisons
128+
snippetsBadge: '{{snippetCount}} snippets'
129+
nav:
130+
allPatterns: ← All patterns
131+
toggleTheme: Toggle theme
132+
viewOnGitHub: View on GitHub
133+
selectLanguage: Select language
134+
breadcrumb:
135+
home: Home
136+
sections:
137+
codeComparison: Code Comparison
138+
whyModernWins: Why the modern way wins
139+
oldApproach: Old Approach
140+
modernApproach: Modern Approach
141+
sinceJdk: Since JDK
142+
difficulty: Difficulty
143+
jdkSupport: JDK Support
144+
howItWorks: How it works
145+
relatedDocs: Related Documentation
146+
relatedPatterns: Related patterns
147+
filters:
148+
show: 'Show:'
149+
all: All
150+
difficulty:
151+
beginner: Beginner
152+
intermediate: Intermediate
153+
advanced: Advanced
154+
search:
155+
placeholder: Search snippets…
156+
noResults: No results found.
157+
esc: ESC
158+
searchTrigger: Search…
159+
navigate: navigate
160+
open: open
161+
close: close
162+
cards:
163+
old: Old
164+
modern: Modern
165+
hoverHint: hover to see modern →
166+
hoverHintRelated: Hover to see modern ➜
167+
touchHint: 👆 tap or swipe →
168+
copy:
169+
copy: Copy
170+
copied: Copied!
171+
share:
172+
label: Share
173+
view:
174+
expandAll: Expand All
175+
collapseAll: Collapse All
176+
stats:
177+
modernPatterns: Modern Patterns
178+
jdkVersions: JDK Versions Covered
179+
categories: Categories
180+
linesOfPython: Lines of Python Required
181+
footer:
182+
tagline: Java has evolved. Your code can too.
183+
madeWith: Made with ❤️ by
184+
and: and
185+
inspiredBy: Inspired by
186+
viewOnGitHub: View on GitHub
187+
copilot:
188+
headline: Modernize your Java codebase with GitHub Copilot.
189+
description: Let Copilot help you migrate legacy patterns to modern Java — automatically.
190+
appModernization: App Modernization →
191+
javaGuide: Java Guide →
192+
support:
193+
available: Available
194+
preview: Preview
195+
experimental: Experimental
196+
contribute:
197+
button: Contribute
198+
codeIssue: Report a code issue
199+
translationIssue: Report a translation issue
200+
suggestPattern: Suggest a new pattern
201+
seeIssue: "See a problem with this code?"
202+
reportIt: "Let us know."
203+
untranslated:
204+
notice: This page has not yet been translated into {{localeName}}.
205+
viewInEnglish: View in English
163206
```
164207
165-
```json
166-
// translations/strings/pt-BR.json (partial — only translated keys required)
167-
{
168-
"site": {
169-
"tagline": "O Java evoluiu. Seu código também pode.",
170-
"description": "Uma coleção de snippets modernos de Java..."
171-
},
172-
"nav": {
173-
"allPatterns": "← Todos os padrões",
174-
"toggleTheme": "Alternar tema"
175-
},
176-
"sections": {
177-
"codeComparison": "Comparação de código",
178-
"whyModernWins": "Por que a forma moderna ganha",
179-
"howItWorks": "Como funciona",
180-
"relatedDocs": "Documentação relacionada",
181-
"relatedPatterns": "Padrões relacionados"
182-
}
183-
}
208+
```yaml
209+
# translations/strings/pt-BR.yaml (partial — only translated keys required)
210+
site:
211+
tagline: O Java evoluiu. Seu código também pode.
212+
description: Uma coleção de snippets modernos de Java...
213+
nav:
214+
allPatterns: ← Todos os padrões
215+
toggleTheme: Alternar tema
216+
sections:
217+
codeComparison: Comparação de código
218+
whyModernWins: Por que a forma moderna ganha
219+
howItWorks: Como funciona
220+
relatedDocs: Documentação relacionada
221+
relatedPatterns: Padrões relacionados
184222
```
185223
186-
**Key-level fallback rule:** if a key present in `en.json` is absent from a
224+
**Key-level fallback rule:** if a key present in `en.yaml` is absent from a
187225
locale file, the generator uses the English value and emits a build-time warning:
188226

189227
```
190-
[WARN] strings/pt-BR.json: missing key "footer.madeWith" — using English fallback
228+
[WARN] pt-BR.yaml: missing key "footer.madeWith" — using English fallback
191229
```
192230

193231
The page is always rendered completely; no key is ever silently blank. The warning
@@ -210,7 +248,7 @@ Every field in a slug definition file falls into one of three categories:
210248
|---|---|---|
211249
| **Translate** (include in translation file) | `title`, `summary`, `explanation`, `oldApproach`, `modernApproach`, `whyModernWins` (full array), `support.description` | These are the **only** fields present in a translation file |
212250
| **English source of truth** (never in translation file) | `id`, `slug`, `category`, `difficulty`, `jdkVersion`, `oldLabel`, `modernLabel`, `oldCode`, `modernCode`, `prev`, `next`, `related`, `docs` | Always taken from the English content file; any values in the translation file are ignored |
213-
| **Translated via UI strings** | `difficulty`, `support.state` | Enum values stay in English; display names resolved from `translations/strings/{locale}.json` at build time |
251+
| **Translated via UI strings** | `difficulty`, `support.state` | Enum values stay in English; display names resolved from `translations/strings/{locale}.yaml` at build time |
214252

215253
**Why enum fields use UI strings instead of content translation:**
216254

@@ -267,8 +305,8 @@ For each pattern and locale the generator:
267305
`whyModernWins`, `support.description`) from the translation file.
268306
- **No** → use the English file and inject an "untranslated" banner
269307
(see next section).
270-
3. Loads `translations/strings/<locale>.json` deep-merged over `en.json`.
271-
Any key present in `en.json` but absent from the locale file falls back to
308+
3. Loads `translations/strings/<locale>.yaml` deep-merged over `en.yaml`.
309+
Any key present in `en.yaml` but absent from the locale file falls back to
272310
the English value; the generator logs a `[WARN]` for each missing key and
273311
continues without aborting.
274312
4. Renders the template, substituting content tokens (`{{title}}`, …) and
@@ -295,7 +333,7 @@ The banner is suppressed when the locale is `en` or a translation file exists.
295333
## Template Changes
296334

297335
Every hard-coded English string in the templates is replaced with a token whose
298-
name mirrors the dot-separated key path in `strings/{locale}.json`:
336+
name mirrors the dot-separated key path in `strings/{locale}.yaml`:
299337

300338
| Before | After |
301339
|---|---|
@@ -516,9 +554,9 @@ mixed freely (e.g., strings in YAML, some content in JSON).
516554

517555
| Phase | Work |
518556
|---|---|
519-
| 1 | Extract every hard-coded string from templates into `translations/strings/en.json`; replace literals with `{{…}}` tokens; verify English output is unchanged |
557+
| 1 | Extract every hard-coded string from templates into `translations/strings/en.yaml`; replace literals with `{{…}}` tokens; verify English output is unchanged |
520558
| 2 | Add `locales.properties`; extend generator to load strings, support `--locale`, and fall back gracefully |
521559
| 3 | Add language selector to nav; implement `app.js` locale detection and path rewrite |
522-
| 4 | Translate `strings/pt-BR.json` and 2–3 content files as a proof-of-concept; verify fallback banner |
560+
| 4 | Translate `strings/pt-BR.yaml` and 2–3 content files as a proof-of-concept; verify fallback banner |
523561
| 5 | Update GitHub Actions; add `hreflang` alternate links |
524562
| 6 | Wire up AI translation automation; add `translations/` schema documentation |

0 commit comments

Comments
 (0)