Add Spanish (es) language support
Same multihost pattern as fr/pt/ja: its own baseURL/subdomain in hugo.toml, UI string translations, a Cloudflare Pages project/domain/DNS record in infra/, and a leg in the deploy loop. No content posts are translated yet, matching fr/pt/ja's current state.
479f7e2 parent: a74fe0a modified
blog/hugo.toml +30 -14 | @@ -5,12 +5,12 @@ enableRobotsTXT = true | ||
| 5 | 5 | # Multihost: every language below sets its own baseURL, which is what tells |
| 6 | 6 | # Hugo to build each one as a fully separate site (own absolute URLs, no |
| 7 | 7 | # /fr/ path prefix) instead of one shared build with a language-prefixed |
| 8 | -# path. `hugo` then writes public/en/, public/fr/, public/pt/, public/ja/ - | |
| 9 | -# each folder is a complete site meant to be deployed as the docroot of its | |
| 10 | -# own (sub)domain (public/en/ -> mykiwi.blog, public/fr/ -> fr.mykiwi.blog, | |
| 11 | -# etc). A content file with no language suffix (e.g. posts/hello-world.md) | |
| 12 | -# is the English version; translations sit alongside it as | |
| 13 | -# posts/hello-world.fr.md, .pt.md, .ja.md. | |
| 8 | +# path. `hugo` then writes public/en/, public/fr/, public/pt/, public/ja/, | |
| 9 | +# public/es/ - each folder is a complete site meant to be deployed as the | |
| 10 | +# docroot of its own (sub)domain (public/en/ -> mykiwi.blog, public/fr/ -> | |
| 11 | +# fr.mykiwi.blog, etc). A content file with no language suffix (e.g. | |
| 12 | +# posts/hello-world.md) is the English version; translations sit alongside | |
| 13 | +# it as posts/hello-world.fr.md, .pt.md, .ja.md, .es.md. | |
| 14 | 14 | defaultContentLanguage = "en" |
| 15 | 15 | |
| 16 | 16 | [languages.en] |
| @@ -19,23 +19,29 @@ label = "English" | ||
| 19 | 19 | locale = "en-us" |
| 20 | 20 | weight = 1 |
| 21 | 21 | |
| 22 | +[languages.es] | |
| 23 | +baseURL = "https://es.mykiwi.blog/" | |
| 24 | +label = "Español" | |
| 25 | +locale = "es-es" | |
| 26 | +weight = 2 | |
| 27 | + | |
| 22 | 28 | [languages.fr] |
| 23 | 29 | baseURL = "https://fr.mykiwi.blog/" |
| 24 | 30 | label = "Français" |
| 25 | 31 | locale = "fr-fr" |
| 26 | -weight = 2 | |
| 32 | +weight = 3 | |
| 27 | 33 | |
| 28 | 34 | [languages.pt] |
| 29 | 35 | baseURL = "https://pt.mykiwi.blog/" |
| 30 | 36 | label = "Português" |
| 31 | 37 | locale = "pt-br" |
| 32 | -weight = 3 | |
| 38 | +weight = 4 | |
| 33 | 39 | |
| 34 | 40 | [languages.ja] |
| 35 | 41 | baseURL = "https://ja.mykiwi.blog/" |
| 36 | 42 | label = "日本語" |
| 37 | 43 | locale = "ja-jp" |
| 38 | -weight = 4 | |
| 44 | +weight = 5 | |
| 39 | 45 | |
| 40 | 46 | [params] |
| 41 | 47 | # Optional: overrides the <meta name="description"> tag with different text |
| @@ -62,24 +68,34 @@ atprotoHandle = 'mykiwi.dev' | ||
| 62 | 68 | bio = "I'm a software engineer, passionate about technology, sharing knowledge and open source like #PHP, #Symfony, #Docker, #Dagger, #Nix and atproto:// Also [🐕️ & 🐈️](https://instagram.com/apy.leon \"Pictures of Apy & Léon\") dad." |
| 63 | 69 | |
| 64 | 70 | [[params.profile.links]] |
| 65 | -key = "bluesky" | |
| 71 | +key = "Tweets on ATmosphere" | |
| 66 | 72 | value = "@mykiwi.dev" |
| 67 | 73 | url = "https://bsky.app/profile/mykiwi.dev" |
| 68 | 74 | |
| 69 | 75 | [[params.profile.links]] |
| 70 | -key = "tangled" | |
| 76 | +key = "Tweets on Fediverse" | |
| 77 | +value = "@mykiwi@mamot.fr" | |
| 78 | +url = "https://mamot.fr/@mykiwi" | |
| 79 | + | |
| 80 | +[[params.profile.links]] | |
| 81 | +key = "Tweets on Twitter" | |
| 82 | +value = "@mykiwi" | |
| 83 | +url = "https://x.com/mykiwi" | |
| 84 | + | |
| 85 | +[[params.profile.links]] | |
| 86 | +key = "Code on ATmosphere" | |
| 71 | 87 | value = "@mykiwi.dev" |
| 72 | 88 | url = "https://tangled.org/mykiwi.dev" |
| 73 | 89 | |
| 74 | 90 | [[params.profile.links]] |
| 75 | -key = "github" | |
| 76 | -value = "mykiwi" | |
| 91 | +key = "Code on GitHub" | |
| 92 | +value = "@mykiwi" | |
| 77 | 93 | url = "https://github.com/mykiwi" |
| 78 | 94 | |
| 79 | 95 | [[params.profile.links]] |
| 80 | 96 | key = "email" |
| 81 | 97 | value = "hi@mykiwi.blog" |
| 82 | -url = "mailto:you@example.com" | |
| 98 | +url = "mailto:hi@mykiwi.blog" | |
| 83 | 99 | |
| 84 | 100 | [markup.highlight] |
| 85 | 101 | noClasses = false |
| @@ -5,12 +5,12 @@ enableRobotsTXT = true | |||
| 5 | # Multihost: every language below sets its own baseURL, which is what tells | 5 | # Multihost: every language below sets its own baseURL, which is what tells |
| 6 | # Hugo to build each one as a fully separate site (own absolute URLs, no | 6 | # Hugo to build each one as a fully separate site (own absolute URLs, no |
| 7 | # /fr/ path prefix) instead of one shared build with a language-prefixed | 7 | # /fr/ path prefix) instead of one shared build with a language-prefixed |
| 8 | -# path. `hugo` then writes public/en/, public/fr/, public/pt/, public/ja/ - | 8 | +# path. `hugo` then writes public/en/, public/fr/, public/pt/, public/ja/, |
| 9 | -# each folder is a complete site meant to be deployed as the docroot of its | 9 | +# public/es/ - each folder is a complete site meant to be deployed as the |
| 10 | -# own (sub)domain (public/en/ -> mykiwi.blog, public/fr/ -> fr.mykiwi.blog, | 10 | +# docroot of its own (sub)domain (public/en/ -> mykiwi.blog, public/fr/ -> |
| 11 | -# etc). A content file with no language suffix (e.g. posts/hello-world.md) | 11 | +# fr.mykiwi.blog, etc). A content file with no language suffix (e.g. |
| 12 | -# is the English version; translations sit alongside it as | 12 | +# posts/hello-world.md) is the English version; translations sit alongside |
| 13 | -# posts/hello-world.fr.md, .pt.md, .ja.md. | 13 | +# it as posts/hello-world.fr.md, .pt.md, .ja.md, .es.md. |
| 14 | defaultContentLanguage = "en" | 14 | defaultContentLanguage = "en" |
| 15 | 15 | ||
| 16 | [languages.en] | 16 | [languages.en] |
| @@ -19,23 +19,29 @@ label = "English" | |||
| 19 | locale = "en-us" | 19 | locale = "en-us" |
| 20 | weight = 1 | 20 | weight = 1 |
| 21 | 21 | ||
| 22 | +[languages.es] | ||
| 23 | +baseURL = "https://es.mykiwi.blog/" | ||
| 24 | +label = "Español" | ||
| 25 | +locale = "es-es" | ||
| 26 | +weight = 2 | ||
| 27 | + | ||
| 22 | [languages.fr] | 28 | [languages.fr] |
| 23 | baseURL = "https://fr.mykiwi.blog/" | 29 | baseURL = "https://fr.mykiwi.blog/" |
| 24 | label = "Français" | 30 | label = "Français" |
| 25 | locale = "fr-fr" | 31 | locale = "fr-fr" |
| 26 | -weight = 2 | 32 | +weight = 3 |
| 27 | 33 | ||
| 28 | [languages.pt] | 34 | [languages.pt] |
| 29 | baseURL = "https://pt.mykiwi.blog/" | 35 | baseURL = "https://pt.mykiwi.blog/" |
| 30 | label = "Português" | 36 | label = "Português" |
| 31 | locale = "pt-br" | 37 | locale = "pt-br" |
| 32 | -weight = 3 | 38 | +weight = 4 |
| 33 | 39 | ||
| 34 | [languages.ja] | 40 | [languages.ja] |
| 35 | baseURL = "https://ja.mykiwi.blog/" | 41 | baseURL = "https://ja.mykiwi.blog/" |
| 36 | label = "日本語" | 42 | label = "日本語" |
| 37 | locale = "ja-jp" | 43 | locale = "ja-jp" |
| 38 | -weight = 4 | 44 | +weight = 5 |
| 39 | 45 | ||
| 40 | [params] | 46 | [params] |
| 41 | # Optional: overrides the <meta name="description"> tag with different text | 47 | # Optional: overrides the <meta name="description"> tag with different text |
| @@ -62,24 +68,34 @@ atprotoHandle = 'mykiwi.dev' | |||
| 62 | bio = "I'm a software engineer, passionate about technology, sharing knowledge and open source like #PHP, #Symfony, #Docker, #Dagger, #Nix and atproto:// Also [🐕️ & 🐈️](https://instagram.com/apy.leon \"Pictures of Apy & Léon\") dad." | 68 | bio = "I'm a software engineer, passionate about technology, sharing knowledge and open source like #PHP, #Symfony, #Docker, #Dagger, #Nix and atproto:// Also [🐕️ & 🐈️](https://instagram.com/apy.leon \"Pictures of Apy & Léon\") dad." |
| 63 | 69 | ||
| 64 | [[params.profile.links]] | 70 | [[params.profile.links]] |
| 65 | -key = "bluesky" | 71 | +key = "Tweets on ATmosphere" |
| 66 | value = "@mykiwi.dev" | 72 | value = "@mykiwi.dev" |
| 67 | url = "https://bsky.app/profile/mykiwi.dev" | 73 | url = "https://bsky.app/profile/mykiwi.dev" |
| 68 | 74 | ||
| 69 | [[params.profile.links]] | 75 | [[params.profile.links]] |
| 70 | -key = "tangled" | 76 | +key = "Tweets on Fediverse" |
| 77 | +value = "@mykiwi@mamot.fr" | ||
| 78 | +url = "https://mamot.fr/@mykiwi" | ||
| 79 | + | ||
| 80 | +[[params.profile.links]] | ||
| 81 | +key = "Tweets on Twitter" | ||
| 82 | +value = "@mykiwi" | ||
| 83 | +url = "https://x.com/mykiwi" | ||
| 84 | + | ||
| 85 | +[[params.profile.links]] | ||
| 86 | +key = "Code on ATmosphere" | ||
| 71 | value = "@mykiwi.dev" | 87 | value = "@mykiwi.dev" |
| 72 | url = "https://tangled.org/mykiwi.dev" | 88 | url = "https://tangled.org/mykiwi.dev" |
| 73 | 89 | ||
| 74 | [[params.profile.links]] | 90 | [[params.profile.links]] |
| 75 | -key = "github" | 91 | +key = "Code on GitHub" |
| 76 | -value = "mykiwi" | 92 | +value = "@mykiwi" |
| 77 | url = "https://github.com/mykiwi" | 93 | url = "https://github.com/mykiwi" |
| 78 | 94 | ||
| 79 | [[params.profile.links]] | 95 | [[params.profile.links]] |
| 80 | key = "email" | 96 | key = "email" |
| 81 | value = "hi@mykiwi.blog" | 97 | value = "hi@mykiwi.blog" |
| 82 | -url = "mailto:you@example.com" | 98 | +url = "mailto:hi@mykiwi.blog" |
| 83 | 99 | ||
| 84 | [markup.highlight] | 100 | [markup.highlight] |
| 85 | noClasses = false | 101 | noClasses = false |
added
blog/i18n/es.toml +27 -0 | new file mode 100644 | ||
| @@ -0,0 +1,27 @@ | ||
| 1 | +[skipToContent] | |
| 2 | +other = "Saltar al contenido" | |
| 3 | + | |
| 4 | +[about] | |
| 5 | +other = "Acerca de" | |
| 6 | + | |
| 7 | +[minRead] | |
| 8 | +other = "{{ .Count }} min de lectura" | |
| 9 | + | |
| 10 | +[postsCount] | |
| 11 | +one = "{{ .Count }} artículo" | |
| 12 | +other = "{{ .Count }} artículos" | |
| 13 | + | |
| 14 | +[licenseText] | |
| 15 | +other = "Texto bajo licencia" | |
| 16 | + | |
| 17 | +[subscribeRSS] | |
| 18 | +other = "Suscribirse vía RSS" | |
| 19 | + | |
| 20 | +[rssLabel] | |
| 21 | +other = "RSS" | |
| 22 | + | |
| 23 | +[latest] | |
| 24 | +other = "Último" | |
| 25 | + | |
| 26 | +[readMore] | |
| 27 | +other = "Leer →" | |
| new file mode 100644 | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | +[skipToContent] | ||
| 2 | +other = "Saltar al contenido" | ||
| 3 | + | ||
| 4 | +[about] | ||
| 5 | +other = "Acerca de" | ||
| 6 | + | ||
| 7 | +[minRead] | ||
| 8 | +other = "{{ .Count }} min de lectura" | ||
| 9 | + | ||
| 10 | +[postsCount] | ||
| 11 | +one = "{{ .Count }} artículo" | ||
| 12 | +other = "{{ .Count }} artículos" | ||
| 13 | + | ||
| 14 | +[licenseText] | ||
| 15 | +other = "Texto bajo licencia" | ||
| 16 | + | ||
| 17 | +[subscribeRSS] | ||
| 18 | +other = "Suscribirse vía RSS" | ||
| 19 | + | ||
| 20 | +[rssLabel] | ||
| 21 | +other = "RSS" | ||
| 22 | + | ||
| 23 | +[latest] | ||
| 24 | +other = "Último" | ||
| 25 | + | ||
| 26 | +[readMore] | ||
| 27 | +other = "Leer →" | ||
modified
flake.nix +1 -1 | @@ -90,7 +90,7 @@ | ||
| 90 | 90 | root="$(git rev-parse --show-toplevel)" |
| 91 | 91 | link="$(mktemp -d)/result" |
| 92 | 92 | nix build "$root#default" --out-link "$link" |
| 93 | - for lang in en fr pt ja; do | |
| 93 | + for lang in en fr pt ja es; do | |
| 94 | 94 | project="mykiwi-blog-$lang" |
| 95 | 95 | echo "==> deploying $lang -> $project" |
| 96 | 96 | wrangler pages deploy "$link/$lang" --project-name="$project" --branch=main |
| @@ -90,7 +90,7 @@ | |||
| 90 | root="$(git rev-parse --show-toplevel)" | 90 | root="$(git rev-parse --show-toplevel)" |
| 91 | link="$(mktemp -d)/result" | 91 | link="$(mktemp -d)/result" |
| 92 | nix build "$root#default" --out-link "$link" | 92 | nix build "$root#default" --out-link "$link" |
| 93 | - for lang in en fr pt ja; do | 93 | + for lang in en fr pt ja es; do |
| 94 | project="mykiwi-blog-$lang" | 94 | project="mykiwi-blog-$lang" |
| 95 | echo "==> deploying $lang -> $project" | 95 | echo "==> deploying $lang -> $project" |
| 96 | wrangler pages deploy "$link/$lang" --project-name="$project" --branch=main | 96 | wrangler pages deploy "$link/$lang" --project-name="$project" --branch=main |
modified
infra/README.md +3 -2 | @@ -3,8 +3,9 @@ | ||
| 3 | 3 | OpenTofu config for the Cloudflare side of the multihost setup in |
| 4 | 4 | `blog/hugo.toml`: one Cloudflare Pages project, custom domain, and DNS |
| 5 | 5 | record per language (`mykiwi.blog`, `fr.mykiwi.blog`, `pt.mykiwi.blog`, |
| 6 | -`ja.mykiwi.blog`). It assumes `mykiwi.blog` is already a zone in your | |
| 7 | -Cloudflare account - this only manages what's *inside* that zone. | |
| 6 | +`ja.mykiwi.blog`, `es.mykiwi.blog`). It assumes `mykiwi.blog` is already | |
| 7 | +a zone in your Cloudflare account - this only manages what's *inside* | |
| 8 | +that zone. | |
| 8 | 9 | |
| 9 | 10 | Deploys (`wrangler pages deploy public/<lang> --project-name=...`) are out |
| 10 | 11 | of scope here; this just provisions the projects and domains deploys land |
| @@ -3,8 +3,9 @@ | |||
| 3 | OpenTofu config for the Cloudflare side of the multihost setup in | 3 | OpenTofu config for the Cloudflare side of the multihost setup in |
| 4 | `blog/hugo.toml`: one Cloudflare Pages project, custom domain, and DNS | 4 | `blog/hugo.toml`: one Cloudflare Pages project, custom domain, and DNS |
| 5 | record per language (`mykiwi.blog`, `fr.mykiwi.blog`, `pt.mykiwi.blog`, | 5 | record per language (`mykiwi.blog`, `fr.mykiwi.blog`, `pt.mykiwi.blog`, |
| 6 | -`ja.mykiwi.blog`). It assumes `mykiwi.blog` is already a zone in your | 6 | +`ja.mykiwi.blog`, `es.mykiwi.blog`). It assumes `mykiwi.blog` is already |
| 7 | -Cloudflare account - this only manages what's *inside* that zone. | 7 | +a zone in your Cloudflare account - this only manages what's *inside* |
| 8 | +that zone. | ||
| 8 | 9 | ||
| 9 | Deploys (`wrangler pages deploy public/<lang> --project-name=...`) are out | 10 | Deploys (`wrangler pages deploy public/<lang> --project-name=...`) are out |
| 10 | of scope here; this just provisions the projects and domains deploys land | 11 | of scope here; this just provisions the projects and domains deploys land |
modified
infra/main.tf +1 -0 | @@ -8,6 +8,7 @@ locals { | ||
| 8 | 8 | fr = { hostname = "fr.${var.zone_name}", project_name = "mykiwi-blog-fr" } |
| 9 | 9 | pt = { hostname = "pt.${var.zone_name}", project_name = "mykiwi-blog-pt" } |
| 10 | 10 | ja = { hostname = "ja.${var.zone_name}", project_name = "mykiwi-blog-ja" } |
| 11 | + es = { hostname = "es.${var.zone_name}", project_name = "mykiwi-blog-es" } | |
| 11 | 12 | } |
| 12 | 13 | } |
| 13 | 14 | |
| @@ -8,6 +8,7 @@ locals { | |||
| 8 | fr = { hostname = "fr.${var.zone_name}", project_name = "mykiwi-blog-fr" } | 8 | fr = { hostname = "fr.${var.zone_name}", project_name = "mykiwi-blog-fr" } |
| 9 | pt = { hostname = "pt.${var.zone_name}", project_name = "mykiwi-blog-pt" } | 9 | pt = { hostname = "pt.${var.zone_name}", project_name = "mykiwi-blog-pt" } |
| 10 | ja = { hostname = "ja.${var.zone_name}", project_name = "mykiwi-blog-ja" } | 10 | ja = { hostname = "ja.${var.zone_name}", project_name = "mykiwi-blog-ja" } |
| 11 | + es = { hostname = "es.${var.zone_name}", project_name = "mykiwi-blog-es" } | ||
| 11 | } | 12 | } |
| 12 | } | 13 | } |
| 13 | 14 | ||