rastrillo / fiesta Public

The landing page's strings: reviewed English and ten drafted translations

Human

Prompt

Task 3 of Fiesta part 3: put the 86 English strings copy review approved into the landing page's catalog byte for byte, give internal/www its Languages, Dir, RequiredKeys and Strings with their tests, machine-draft the ten other languages from the approved English, and give the fiesta site fixture a landing/strings/ stub.

From this commit's own message. The prompt ledger has no entries for it — which is what a squashed, rebased or amended commit looks like, and what every commit looks like in a repo without a ledger.

Summary

site/landing/strings/en.json holds the 86 approved strings, keyed without the landing. prefix; the headline, the lede and the install line are Paul's words verbatim. internal/www/strings.go declares the eleven site languages, Dir (rtl for Arabic), the sorted RequiredKeys, and Strings, which reads one catalog from the site source and refuses one that is missing, lacks a key, holds a key the page never reads, writes a key twice, leaves a value empty, or drops or adds a {placeholder} the English string has; every error names the key. The ten other catalogs, ar bn es ga hi ja pt-PT ru vi zh-Hans, are machine drafts from the approved English that nobody has reviewed: where a key matches the mockup's I18N dictionaries they start from those, and the 26 keys the mockup lacked, the title, description, skip link, landmark names, Copied, the copy failure, the sample's two local confirmations, Courses and the twelve footer strings, are drafted fresh. The theme names Day, Plain and Signal and The Eleven Factors stay as written in every language. TestSiteWritesWhatBuildReturns' site fixture now carries a complete catalog per language, so it is a whole site source once the landing page reads them.
Agent notes
TestEveryLanguageHasEveryKey, TestPaulsWordsAreVerbatim and TestThePlaceholdersSurviveTranslation were red by name against a Strings that returned an empty catalog, then green. The placeholder test is carried by its fixture, since no real string has a placeholder today. Brand names stay in Latin script in every draft. The Arabic install line keeps the mockup's isolates around <25KiB so the figure reads left to right. make ci was green in a clean worktree before this commit.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev f59b6f3f37ba4c7034ae663e2cb820aad1b04eba parent 5a5c77a
14 files changed, +1381 −0
  • cmd/fiesta/release_test.go +21 −0
  • internal/www/strings.go +217 −0
  • internal/www/strings_test.go +175 −0
  • site/landing/strings/ar.json +88 −0
  • site/landing/strings/bn.json +88 −0
  • site/landing/strings/en.json +88 −0
  • site/landing/strings/es.json +88 −0
  • site/landing/strings/ga.json +88 −0
  • site/landing/strings/hi.json +88 −0
  • site/landing/strings/ja.json +88 −0
  • site/landing/strings/pt-PT.json +88 −0
  • site/landing/strings/ru.json +88 −0
  • site/landing/strings/vi.json +88 −0
  • site/landing/strings/zh-Hans.json +88 −0

CI passed — run details

CI log
=== gofmt ===
=== no-rastrillo ===
go test -run '^(TestFiestaNeverImportsRastrillo|TestThePublicPackagesLinkNoBrowser)$' -count=1 .
ok  	amadan.net/rastrillo/fiesta	0.270s
=== size ===
go test ./internal/build -run '^TestTheOneLinkIsUnder25KiBGzipped$' -count=1 -v
=== RUN   TestTheOneLinkIsUnder25KiBGzipped
    build_test.go:138: fiesta-plain.css: 152856 bytes, 22303 bytes gzipped (21.8 KiB of the 25.0 KiB limit)
    build_test.go:138: fiesta-signal.css: 152951 bytes, 22414 bytes gzipped (21.9 KiB of the 25.0 KiB limit)
    build_test.go:138: fiesta.css: 155770 bytes, 23018 bytes gzipped (22.5 KiB of the 25.0 KiB limit)
--- PASS: TestTheOneLinkIsUnder25KiBGzipped (0.04s)
PASS
ok  	amadan.net/rastrillo/fiesta/internal/build	0.046s
=== suite ===
--- shard 0 of 12 ---
==> shard 0 of 12: make root
go build ./...
go vet ./...
FIESTA_TEST_REQUIRE_NODE=1 FIESTA_TEST_REQUIRE_GIT=1 go test -count=1 ./...
ok  	amadan.net/rastrillo/fiesta	1.206s
ok  	amadan.net/rastrillo/fiesta/check	4.874s
ok  	amadan.net/rastrillo/fiesta/cmd/fiesta	5.949s
ok  	amadan.net/rastrillo/fiesta/example	0.278s
ok  	amadan.net/rastrillo/fiesta/internal/axe	0.102s
ok  	amadan.net/rastrillo/fiesta/internal/build	1.326s
ok  	amadan.net/rastrillo/fiesta/internal/codeview	0.020s
ok  	amadan.net/rastrillo/fiesta/internal/gallery	5.094s
?   	amadan.net/rastrillo/fiesta/internal/harness	[no test files]
ok  	amadan.net/rastrillo/fiesta/internal/markup	0.009s
ok  	amadan.net/rastrillo/fiesta/internal/nodetest	0.398s
ok  	amadan.net/rastrillo/fiesta/internal/site	3.439s
ok  	amadan.net/rastrillo/fiesta/internal/tokens	0.006s
ok  	amadan.net/rastrillo/fiesta/internal/www	2.239s
--- shard 1 of 12 ---
==> shard 1 of 12: make staticcheck
go run honnef.co/go/tools/cmd/staticcheck@v0.8.2 -tags browser ./...
--- shard 2 of 12 ---
==> shard 2 of 12: make govulncheck
go run golang.org/x/vuln/cmd/govulncheck@v1.8.0 ./...
=== Symbol Results ===

No vulnerabilities found.

Your code is affected by 0 vulnerabilities.
This scan also found 2 vulnerabilities in packages you import and 5
vulnerabilities in modules you require, but your code doesn't appear to call
these vulnerabilities.
Use '-show verbose' for more details.
--- shard 3 of 12 ---
==> shard 3 of 12: make gitleaks
go run github.com/zricethezav/gitleaks/v8@v8.30.1 git --no-banner --redact --log-opts='--full-history --diff-filter=tuxdb HEAD' .
4:30PM INF Unknown SCM platform. Use --platform to include links in findings. host=amadan.net
4:31PM INF 1 commits scanned.
4:31PM INF scanned ~5662755 bytes (5.66 MB) in 3.74s
4:31PM INF no leaks found
--- shard 4 of 12 ---
==> shard 4 of 12: make browser.internal.harness
./hack/gotest.sh browser 'internal.harness'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
ok  	amadan.net/rastrillo/fiesta/internal/harness	11.051s
--- shard 5 of 12 ---
==> shard 5 of 12: make browser.check~1of3
./hack/gotest.sh browser 'check~1of3'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
gotest: slice 1 of 3 of ./check/ runs 95 of 286 tests
ok  	amadan.net/rastrillo/fiesta/check	194.533s
--- shard 6 of 12 ---
==> shard 6 of 12: make browser.check~2of3
./hack/gotest.sh browser 'check~2of3'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
gotest: slice 2 of 3 of ./check/ runs 95 of 286 tests
ok  	amadan.net/rastrillo/fiesta/check	207.317s
--- shard 7 of 12 ---
==> shard 7 of 12: make browser.check~3of3
./hack/gotest.sh browser 'check~3of3'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
gotest: slice 3 of 3 of ./check/ runs 96 of 286 tests
ok  	amadan.net/rastrillo/fiesta/check	207.602s
--- shard 8 of 12 ---
==> shard 8 of 12: make browser.internal.gallery~1of2
./hack/gotest.sh browser 'internal.gallery~1of2'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
gotest: slice 1 of 2 of ./internal/gallery/ runs 1 of 25 tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	73.943s
--- shard 9 of 12 ---
==> shard 9 of 12: make browser.internal.gallery~2of2
./hack/gotest.sh browser 'internal.gallery~2of2'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
gotest: slice 2 of 2 of ./internal/gallery/ runs 24 of 25 tests
ok  	amadan.net/rastrillo/fiesta/internal/gallery	32.694s
--- shard 10 of 12 ---
==> shard 10 of 12: make browser.internal.www~1of2
./hack/gotest.sh browser 'internal.www~1of2'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
gotest: slice 1 of 2 of ./internal/www/ runs 4 of 8 tests
ok  	amadan.net/rastrillo/fiesta/internal/www	2.535s
--- shard 11 of 12 ---
==> shard 11 of 12: make browser.internal.www~2of2
./hack/gotest.sh browser 'internal.www~2of2'
gotest: on DOCS-T1, driving the harness's own choice (/usr/bin/chromium)
gotest: slice 2 of 2 of ./internal/www/ runs 4 of 8 tests
ok  	amadan.net/rastrillo/fiesta/internal/www	0.539s
diff --git a/cmd/fiesta/release_test.go b/cmd/fiesta/release_test.go
index 9bef951..5614bbe 100644
--- a/cmd/fiesta/release_test.go
+++ b/cmd/fiesta/release_test.go
@@ -2,6 +2,7 @@ package main
import (
"bytes"
+ "encoding/json"
"fmt"
"io"
"os"
@@ -374,6 +375,26 @@ func TestSiteWritesWhatBuildReturns(t *testing.T) {
if err := os.WriteFile(filepath.Join(siteDir, "static", "x.css"), []byte("body{margin:0}\n"), 0o644); err != nil {
t.Fatal(err)
}
+ // The landing page's catalogs, one per language, each complete and
+ // valued by its keys: a stand-in for site/landing/strings/ that
+ // www.Strings accepts, so the fixture is a whole site source.
+ catalogs := filepath.Join(siteDir, "landing", "strings")
+ if err := os.MkdirAll(catalogs, 0o755); err != nil {
+ t.Fatal(err)
+ }
+ catalog := map[string]string{}
+ for _, key := range www.RequiredKeys {
+ catalog[key] = key
+ }
+ stub, err := json.Marshal(catalog)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, lang := range www.Languages {
+ if err := os.WriteFile(filepath.Join(catalogs, lang+".json"), stub, 0o644); err != nil {
+ t.Fatal(err)
+ }
+ }
out := filepath.Join(root, "out", "site")
if err := run([]string{"site", "-releases", releases, "-site", siteDir, "-out", out}, io.Discard); err != nil {
t.Fatalf("fiesta site: %v", err)
diff --git a/internal/www/strings.go b/internal/www/strings.go
new file mode 100644
index 0000000..b9322a6
--- /dev/null
+++ b/internal/www/strings.go
@@ -0,0 +1,217 @@
+package www
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/fs"
+ "path"
+ "regexp"
+ "slices"
+ "strings"
+)
+
+// Languages is every language the landing page is built in, English
+// first and the rest in code order. Arabic is written right to left.
+// yue is in Fiesta's own string tables but is not a site language.
+var Languages = []string{"en", "ar", "bn", "es", "ga", "hi", "ja", "pt-PT", "ru", "vi", "zh-Hans"}
+
+// Dir is the direction lang is written in, as the html element's dir
+// attribute wants it: rtl for Arabic, ltr for everything else.
+func Dir(lang string) string {
+ if lang == "ar" {
+ return "rtl"
+ }
+ return "ltr"
+}
+
+// RequiredKeys is every key a landing page catalog holds, sorted. A
+// catalog has exactly these: a key the page would render empty, or one
+// the page never reads, is a mistake Strings reports.
+var RequiredKeys = []string{
+ "copied",
+ "copy",
+ "copy.failed",
+ "cta.see",
+ "cta.themes",
+ "description",
+ "foot.carlos.framework",
+ "foot.carlos.platform",
+ "foot.carlos.start",
+ "foot.docs",
+ "foot.eleven",
+ "foot.letters",
+ "foot.licence",
+ "foot.principles",
+ "foot.source",
+ "foot.tagline",
+ "foot.trust",
+ "foot.version",
+ "headline",
+ "install",
+ "lang.label",
+ "lede",
+ "nav.design",
+ "nav.label",
+ "nav.start",
+ "nav.themes",
+ "sample.cancel",
+ "sample.coming",
+ "sample.courses",
+ "sample.desserts",
+ "sample.dish.glutenfree",
+ "sample.dish.nuts",
+ "sample.dish.vegetarian",
+ "sample.dishes",
+ "sample.email",
+ "sample.export",
+ "sample.fade",
+ "sample.guest.noreply",
+ "sample.guest.plusone",
+ "sample.guest.vegetarian",
+ "sample.guests",
+ "sample.invite",
+ "sample.invited",
+ "sample.label",
+ "sample.mains",
+ "sample.menu",
+ "sample.music",
+ "sample.nav.label",
+ "sample.next",
+ "sample.next.body",
+ "sample.overview",
+ "sample.partyname",
+ "sample.playing",
+ "sample.public",
+ "sample.reminders",
+ "sample.save",
+ "sample.saved",
+ "sample.search",
+ "sample.searched",
+ "sample.settings",
+ "sample.shuffle",
+ "sample.songs",
+ "sample.starters",
+ "sample.timezone",
+ "scheme.dark",
+ "scheme.label",
+ "scheme.light",
+ "scheme.system",
+ "skip",
+ "theme.day",
+ "theme.label",
+ "theme.plain",
+ "theme.signal",
+ "title",
+ "why.a11y.body",
+ "why.a11y.title",
+ "why.attrs.body",
+ "why.attrs.title",
+ "why.dark.body",
+ "why.dark.title",
+ "why.depth.body",
+ "why.depth.title",
+ "why.link.body",
+ "why.link.title",
+ "why.rtl.body",
+ "why.rtl.title",
+}
+
+// stringsDir is the directory under the site source holding the
+// landing page's catalogs, one <lang>.json each: a JSON object from
+// key to string, nothing else.
+const stringsDir = "landing/strings"
+
+// placeholder is a {name} a template fills in. The English string
+// decides which placeholders a key has; a translation holds the same
+// ones, or the page would say something different in that language.
+var placeholder = regexp.MustCompile(`\{[^{}]*\}`)
+
+// Strings reads the landing page's catalog for lang from the site
+// source, landing/strings/<lang>.json, and returns it key by key. It
+// refuses a catalog that is missing, that lacks a required key or
+// holds one the page never reads, that leaves a value empty, or that
+// drops or adds a placeholder the English string has; each error names
+// the key. English is read alongside every other language for the
+// placeholder check.
+func Strings(siteDir fs.FS, lang string) (map[string]string, error) {
+ out, err := catalog(siteDir, lang)
+ if err != nil {
+ return nil, err
+ }
+ if lang == "en" {
+ return out, nil
+ }
+ en, err := catalog(siteDir, "en")
+ if err != nil {
+ return nil, err
+ }
+ for _, key := range RequiredKeys {
+ want, got := placeholder.FindAllString(en[key], -1), placeholder.FindAllString(out[key], -1)
+ slices.Sort(want)
+ slices.Sort(got)
+ if !slices.Equal(want, got) {
+ return nil, fmt.Errorf("www: %s: %s has placeholders %v, but the English has %v", name(lang), key, got, want)
+ }
+ }
+ return out, nil
+}
+
+// name is the catalog's path under the site source.
+func name(lang string) string {
+ return path.Join(stringsDir, lang+".json")
+}
+
+// catalog reads one language's catalog and checks it against
+// RequiredKeys. It decodes token by token rather than into a map, so
+// a key written twice is refused instead of the second quietly
+// winning, and so a value that is not a string is named.
+func catalog(siteDir fs.FS, lang string) (map[string]string, error) {
+ data, err := fs.ReadFile(siteDir, name(lang))
+ if err != nil {
+ return nil, fmt.Errorf("www: reading the %s catalog: %w", lang, err)
+ }
+ dec := json.NewDecoder(bytes.NewReader(data))
+ if tok, err := dec.Token(); err != nil || tok != json.Delim('{') {
+ return nil, fmt.Errorf("www: %s is not a JSON object", name(lang))
+ }
+ out := make(map[string]string, len(RequiredKeys))
+ for dec.More() {
+ tok, err := dec.Token()
+ if err != nil {
+ return nil, fmt.Errorf("www: %s: %w", name(lang), err)
+ }
+ key := tok.(string)
+ if _, dup := out[key]; dup {
+ return nil, fmt.Errorf("www: %s: %s is written twice", name(lang), key)
+ }
+ var value string
+ if err := dec.Decode(&value); err != nil {
+ return nil, fmt.Errorf("www: %s: %s: %w", name(lang), key, err)
+ }
+ if strings.TrimSpace(value) == "" {
+ return nil, fmt.Errorf("www: %s: %s is empty", name(lang), key)
+ }
+ out[key] = value
+ }
+ if _, err := dec.Token(); err != nil {
+ return nil, fmt.Errorf("www: %s: %w", name(lang), err)
+ }
+ if _, err := dec.Token(); err != io.EOF {
+ return nil, fmt.Errorf("www: %s has content after the object", name(lang))
+ }
+ for _, key := range RequiredKeys {
+ if _, ok := out[key]; !ok {
+ return nil, fmt.Errorf("www: %s lacks %s", name(lang), key)
+ }
+ }
+ if len(out) != len(RequiredKeys) {
+ for key := range out {
+ if _, ok := slices.BinarySearch(RequiredKeys, key); !ok {
+ return nil, fmt.Errorf("www: %s has %s, which the page never reads", name(lang), key)
+ }
+ }
+ }
+ return out, nil
+}
diff --git a/internal/www/strings_test.go b/internal/www/strings_test.go
new file mode 100644
index 0000000..353bc9c
--- /dev/null
+++ b/internal/www/strings_test.go
@@ -0,0 +1,175 @@
+package www_test
+
+import (
+ "io/fs"
+ "os"
+ "path/filepath"
+ "slices"
+ "strings"
+ "testing"
+ "testing/fstest"
+
+ "amadan.net/rastrillo/fiesta/internal/www"
+)
+
+// realSite is the repository's site/ directory, the site source the
+// landing page is built from.
+func realSite() fs.FS {
+ return os.DirFS(filepath.Join("..", "..", "site"))
+}
+
+// catalogs is a site source holding one landing catalog per language,
+// each written as Strings reads it.
+func catalogs(t *testing.T, langs map[string]map[string]string) fstest.MapFS {
+ t.Helper()
+ m := fstest.MapFS{}
+ for lang, strs := range langs {
+ var b strings.Builder
+ b.WriteString("{\n")
+ keys := make([]string, 0, len(strs))
+ for k := range strs {
+ keys = append(keys, k)
+ }
+ slices.Sort(keys)
+ for i, k := range keys {
+ if i > 0 {
+ b.WriteString(",\n")
+ }
+ b.WriteString(" " + quote(k) + ": " + quote(strs[k]))
+ }
+ b.WriteString("\n}\n")
+ m["landing/strings/"+lang+".json"] = &fstest.MapFile{Data: []byte(b.String())}
+ }
+ return m
+}
+
+// quote is a JSON string literal, enough for the fixtures here.
+func quote(s string) string {
+ return `"` + strings.NewReplacer(`\`, `\\`, `"`, `\"`, "\n", `\n`).Replace(s) + `"`
+}
+
+// complete is a catalog with every required key, each valued by text.
+func complete(text func(key string) string) map[string]string {
+ out := make(map[string]string, len(www.RequiredKeys))
+ for _, k := range www.RequiredKeys {
+ out[k] = text(k)
+ }
+ return out
+}
+
+// keyItself values a key by its own name.
+func keyItself(key string) string { return key }
+
+// keysOf is m's keys, sorted.
+func keysOf(m map[string]string) []string {
+ keys := make([]string, 0, len(m))
+ for k := range m {
+ keys = append(keys, k)
+ }
+ slices.Sort(keys)
+ return keys
+}
+
+// TestEveryLanguageHasEveryKey: every site language has a catalog in
+// the site source, and each holds exactly RequiredKeys with nothing
+// empty. A catalog that lacks a key, adds one, leaves one empty or is
+// not there at all is refused, and the error names what is wrong.
+func TestEveryLanguageHasEveryKey(t *testing.T) {
+ if !slices.IsSorted(www.RequiredKeys) || len(slices.Compact(slices.Clone(www.RequiredKeys))) != len(www.RequiredKeys) {
+ t.Fatal("RequiredKeys is not sorted and unique")
+ }
+ if len(www.Languages) != 11 || www.Languages[0] != "en" {
+ t.Fatalf("Languages is %v", www.Languages)
+ }
+ for _, lang := range www.Languages {
+ got, err := www.Strings(realSite(), lang)
+ if err != nil {
+ t.Errorf("%s: %v", lang, err)
+ continue
+ }
+ if keys := keysOf(got); !slices.Equal(keys, www.RequiredKeys) {
+ t.Errorf("%s has keys %v, want RequiredKeys", lang, keys)
+ }
+ for k, v := range got {
+ if strings.TrimSpace(v) == "" {
+ t.Errorf("%s: %s is empty", lang, k)
+ }
+ }
+ }
+
+ short := complete(keyItself)
+ delete(short, "sample.saved")
+ _, err := www.Strings(catalogs(t, map[string]map[string]string{"en": short}), "en")
+ if err == nil || !strings.Contains(err.Error(), "sample.saved") {
+ t.Errorf("a catalog lacking sample.saved was accepted, or the error does not name it: %v", err)
+ }
+
+ extra := complete(keyItself)
+ extra["sample.extra"] = "x"
+ _, err = www.Strings(catalogs(t, map[string]map[string]string{"en": extra}), "en")
+ if err == nil || !strings.Contains(err.Error(), "sample.extra") {
+ t.Errorf("a catalog with a key the page never reads was accepted, or the error does not name it: %v", err)
+ }
+
+ blank := complete(keyItself)
+ blank["copied"] = " "
+ _, err = www.Strings(catalogs(t, map[string]map[string]string{"en": blank}), "en")
+ if err == nil || !strings.Contains(err.Error(), "copied") {
+ t.Errorf("a catalog with an empty copied was accepted, or the error does not name it: %v", err)
+ }
+
+ if _, err := www.Strings(catalogs(t, nil), "en"); err == nil {
+ t.Error("a site source with no catalog at all was accepted")
+ }
+
+ if _, err := www.Strings(catalogs(t, map[string]map[string]string{"en": complete(keyItself)}), "en"); err != nil {
+ t.Errorf("the complete control catalog was refused: %v", err)
+ }
+}
+
+// TestPaulsWordsAreVerbatim: the headline, the lede and the install
+// line are Paul's words, byte for byte, in the English catalog.
+func TestPaulsWordsAreVerbatim(t *testing.T) {
+ en, err := www.Strings(realSite(), "en")
+ if err != nil {
+ t.Fatal(err)
+ }
+ for key, want := range map[string]string{
+ "headline": "Celebrate your new design system",
+ "lede": "Polished, accessible, multi-lingual, localised components for everyone.",
+ "install": "One stylesheet and done. JS optional. <25KiB gzipped.",
+ } {
+ if got := en[key]; got != want {
+ t.Errorf("%s is %q, want %q", key, got, want)
+ }
+ }
+}
+
+// TestThePlaceholdersSurviveTranslation: a {name} placeholder in an
+// English string is in its translation too. A Spanish catalog that
+// drops the English {n} is refused by key and placeholder; one that
+// keeps it passes. No real string holds a placeholder today, so the
+// fixture carries this test and the real catalogs merely pass.
+func TestThePlaceholdersSurviveTranslation(t *testing.T) {
+ en := complete(keyItself)
+ en["sample.next.body"] = "Reminders go out on Friday. {n} guests still need a reply."
+
+ dropped := complete(keyItself)
+ dropped["sample.next.body"] = "Los recordatorios salen el viernes. Tres invitados aún no han respondido."
+ _, err := www.Strings(catalogs(t, map[string]map[string]string{"en": en, "es": dropped}), "es")
+ if err == nil || !strings.Contains(err.Error(), "{n}") || !strings.Contains(err.Error(), "sample.next.body") {
+ t.Errorf("a Spanish catalog that drops {n} was accepted, or the error does not name the key and the placeholder: %v", err)
+ }
+
+ kept := complete(keyItself)
+ kept["sample.next.body"] = "Los recordatorios salen el viernes. {n} invitados aún no han respondido."
+ if _, err := www.Strings(catalogs(t, map[string]map[string]string{"en": en, "es": kept}), "es"); err != nil {
+ t.Errorf("a Spanish catalog that keeps {n} was refused: %v", err)
+ }
+
+ for _, lang := range www.Languages {
+ if _, err := www.Strings(realSite(), lang); err != nil {
+ t.Errorf("%s: %v", lang, err)
+ }
+ }
+}
diff --git a/site/landing/strings/ar.json b/site/landing/strings/ar.json
new file mode 100644
index 0000000..1b5d7c4
--- /dev/null
+++ b/site/landing/strings/ar.json
@@ -0,0 +1,88 @@
+{
+ "copied": "تم النسخ",
+ "copy": "نسخ",
+ "copy.failed": "تعذّر النسخ. وسم الرابط محدَّد، فيمكنك نسخه بنفسك.",
+ "cta.see": "استعرض نظام التصميم",
+ "cta.themes": "عرض السمات",
+ "description": "Fiesta نظام تصميم تضيفه برابط ملف أنماط واحد. مكوّنات مصقولة وسهلة الوصول في الوضعين الفاتح والداكن، بإحدى عشرة لغة، ومن اليمين إلى اليسار أيضًا. بلا خطوة بناء، وأقل من 25KiB مضغوطًا بـ gzip.",
+ "foot.carlos.framework": "إطار عمل CARLOS",
+ "foot.carlos.platform": "منصة CARLOS",
+ "foot.carlos.start": "ابدأ مع CARLOS",
+ "foot.docs": "التوثيق",
+ "foot.eleven": "The Eleven Factors",
+ "foot.letters": "الحروف الستة",
+ "foot.licence": "مفتوح المصدر",
+ "foot.principles": "المبادئ",
+ "foot.source": "المصدر",
+ "foot.tagline": "نظام التصميم من Rastrillo، إطار عمل الويب لمشروع CARLOS.",
+ "foot.trust": "الثقة",
+ "foot.version": "الإصدار",
+ "headline": "احتفل بنظام التصميم الجديد",
+ "install": "ملف أنماط واحد وينتهي الأمر. JS اختياري. ⁦<25KiB⁩ مضغوطًا بـ gzip.",
+ "lang.label": "اللغة",
+ "lede": "مكوّنات مصقولة وسهلة الوصول ومتعددة اللغات ومُوطَّنة للجميع.",
+ "nav.design": "نظام التصميم",
+ "nav.label": "الرئيسي",
+ "nav.start": "ابدأ الآن",
+ "nav.themes": "السمات",
+ "sample.cancel": "إلغاء",
+ "sample.coming": "سيحضر",
+ "sample.courses": "أقسام القائمة",
+ "sample.desserts": "الحلويات",
+ "sample.dish.glutenfree": "خالٍ من الغلوتين",
+ "sample.dish.nuts": "يحتوي على مكسرات",
+ "sample.dish.vegetarian": "نباتي",
+ "sample.dishes": "الأطباق",
+ "sample.email": "أرسل لي بريدًا مع كل رد",
+ "sample.export": "تصدير القائمة",
+ "sample.fade": "تلاشٍ بين الأغاني",
+ "sample.guest.noreply": "لم يردّ بعد",
+ "sample.guest.plusone": "سيأتي مع مرافق",
+ "sample.guest.vegetarian": "نباتية",
+ "sample.guests": "الضيوف",
+ "sample.invite": "دعوة ضيوف",
+ "sample.invited": "مدعو",
+ "sample.label": "تطبيق تجريبي مبني بـ Fiesta",
+ "sample.mains": "الأطباق الرئيسية",
+ "sample.menu": "قائمة الطعام",
+ "sample.music": "الموسيقى",
+ "sample.nav.label": "منظّم الحفلات",
+ "sample.next": "التالي",
+ "sample.next.body": "تُرسل التذكيرات يوم الجمعة. ثلاثة ضيوف لم يردّوا بعد.",
+ "sample.overview": "نظرة عامة",
+ "sample.partyname": "اسم الحفلة",
+ "sample.playing": "قيد التشغيل",
+ "sample.public": "صفحة ردود عامة",
+ "sample.reminders": "إرسال تذكير قبل الموعد بيوم",
+ "sample.save": "حفظ",
+ "sample.saved": "تم الحفظ. هذا النموذج بلا خادم، لذا لم يُخزَّن شيء.",
+ "sample.search": "البحث في الضيوف",
+ "sample.searched": "تم البحث. هذا النموذج بلا خادم، لذا تبقى القائمة كما هي.",
+ "sample.settings": "الإعدادات",
+ "sample.shuffle": "تشغيل عشوائي",
+ "sample.songs": "الأغاني",
+ "sample.starters": "المقبلات",
+ "sample.timezone": "المنطقة الزمنية",
+ "scheme.dark": "داكن",
+ "scheme.label": "نظام الألوان",
+ "scheme.light": "فاتح",
+ "scheme.system": "حسب النظام",
+ "skip": "تخطَّ إلى المحتوى",
+ "theme.day": "Day",
+ "theme.label": "السمة",
+ "theme.plain": "Plain",
+ "theme.signal": "Signal",
+ "title": "Fiesta: نظام تصميم في ملف أنماط واحد",
+ "why.a11y.body": "تباين مُتحقَّق منه وفق WCAG، وحلقات تركيز حقيقية، ودعم لوضع التباين العالي والطباعة.",
+ "why.a11y.title": "سهل الوصول افتراضيًا",
+ "why.attrs.body": "يُقرأ كما هو. بلا فوضى أصناف.",
+ "why.attrs.title": "سمات HTML بسيطة",
+ "why.dark.body": "يتبع إعداد النظام أو مفتاحًا تضيفه أنت. كل لون مُراجَع في الوضعين.",
+ "why.dark.title": "فاتح وداكن، مدمجان",
+ "why.depth.body": "الأزرار تنضغط، والبطاقات تلتقط الضوء، والضوء يتبع مؤشرك.",
+ "why.depth.title": "عمق ينبض بالحياة",
+ "why.link.body": "الصق وسم ملف الأنماط. يعمل في أي صفحة، مع أي إطار عمل أو بدونه.",
+ "why.link.title": "رابط واحد، دون بناء",
+ "why.rtl.body": "العربية والعبرية وكل نظام كتابة آخر تُعرض بشكل صحيح دون أي CSS إضافي.",
+ "why.rtl.title": "جاهز للكتابة من اليمين إلى اليسار"
+}
diff --git a/site/landing/strings/bn.json b/site/landing/strings/bn.json
new file mode 100644
index 0000000..a4419f5
--- /dev/null
+++ b/site/landing/strings/bn.json
@@ -0,0 +1,88 @@
+{
+ "copied": "কপি হয়েছে",
+ "copy": "কপি করুন",
+ "copy.failed": "কপি করা যায়নি। লিংক ট্যাগটি নির্বাচিত আছে, তাই আপনি নিজেই কপি করে নিতে পারেন।",
+ "cta.see": "ডিজাইন সিস্টেম দেখুন",
+ "cta.themes": "থিম দেখুন",
+ "description": "Fiesta এমন একটি ডিজাইন সিস্টেম যা একটি স্টাইলশিট লিংক দিয়েই যোগ করা যায়। ঝকঝকে, অ্যাক্সেসযোগ্য কম্পোনেন্ট, লাইট ও ডার্ক দুই মোডে, এগারোটি ভাষায়, ডান-থেকে-বামেও। কোনো বিল্ড ধাপ নেই, gzip করলে 25KiB-এর কম।",
+ "foot.carlos.framework": "CARLOS ফ্রেমওয়ার্ক",
+ "foot.carlos.platform": "CARLOS প্ল্যাটফর্ম",
+ "foot.carlos.start": "CARLOS দিয়ে শুরু করুন",
+ "foot.docs": "ডকুমেন্টেশন",
+ "foot.eleven": "The Eleven Factors",
+ "foot.letters": "ছয়টি অক্ষর",
+ "foot.licence": "ওপেন সোর্স",
+ "foot.principles": "নীতিমালা",
+ "foot.source": "সোর্স",
+ "foot.tagline": "Rastrillo-র ডিজাইন সিস্টেম; Rastrillo হলো CARLOS প্রকল্পের ওয়েব ফ্রেমওয়ার্ক।",
+ "foot.trust": "বিশ্বাস",
+ "foot.version": "সংস্করণ",
+ "headline": "আপনার নতুন ডিজাইন সিস্টেম উদ্‌যাপন করুন",
+ "install": "একটি স্টাইলশিট, ব্যস। JS ঐচ্ছিক। gzip করলে <25KiB।",
+ "lang.label": "ভাষা",
+ "lede": "সবার জন্য ঝকঝকে, অ্যাক্সেসযোগ্য, বহুভাষিক ও স্থানীয়কৃত কম্পোনেন্ট।",
+ "nav.design": "ডিজাইন সিস্টেম",
+ "nav.label": "প্রধান",
+ "nav.start": "শুরু করুন",
+ "nav.themes": "থিম",
+ "sample.cancel": "বাতিল",
+ "sample.coming": "আসছেন",
+ "sample.courses": "কোর্স",
+ "sample.desserts": "ডেজার্ট",
+ "sample.dish.glutenfree": "গ্লুটেন-মুক্ত",
+ "sample.dish.nuts": "বাদাম আছে",
+ "sample.dish.vegetarian": "নিরামিষ",
+ "sample.dishes": "পদ",
+ "sample.email": "প্রতিটি উত্তরে আমাকে ইমেল করুন",
+ "sample.export": "তালিকা এক্সপোর্ট করুন",
+ "sample.fade": "গানের মাঝে ফেড",
+ "sample.guest.noreply": "এখনও উত্তর নেই",
+ "sample.guest.plusone": "সঙ্গে একজন আসছেন",
+ "sample.guest.vegetarian": "নিরামিষাশী",
+ "sample.guests": "অতিথি",
+ "sample.invite": "অতিথি আমন্ত্রণ করুন",
+ "sample.invited": "আমন্ত্রিত",
+ "sample.label": "Fiesta দিয়ে তৈরি একটি নমুনা অ্যাপ",
+ "sample.mains": "মূল পদ",
+ "sample.menu": "মেনু",
+ "sample.music": "সংগীত",
+ "sample.nav.label": "পার্টি পরিকল্পনা",
+ "sample.next": "এরপর",
+ "sample.next.body": "শুক্রবার রিমাইন্ডার যাবে। তিনজন অতিথি এখনও উত্তর দেননি।",
+ "sample.overview": "সারসংক্ষেপ",
+ "sample.partyname": "পার্টির নাম",
+ "sample.playing": "বাজছে",
+ "sample.public": "সর্বজনীন RSVP পেজ",
+ "sample.reminders": "আগের দিন রিমাইন্ডার পাঠান",
+ "sample.save": "সংরক্ষণ করুন",
+ "sample.saved": "সংরক্ষিত। এই নমুনার কোনো সার্ভার নেই, তাই কিছুই জমা হয়নি।",
+ "sample.search": "অতিথি খুঁজুন",
+ "sample.searched": "খোঁজা হয়েছে। এই নমুনার কোনো সার্ভার নেই, তাই তালিকা যেমন আছে তেমনই থাকবে।",
+ "sample.settings": "সেটিংস",
+ "sample.shuffle": "শাফল",
+ "sample.songs": "গান",
+ "sample.starters": "স্টার্টার",
+ "sample.timezone": "টাইম জোন",
+ "scheme.dark": "গাঢ়",
+ "scheme.label": "রঙের ধরন",
+ "scheme.light": "হালকা",
+ "scheme.system": "সিস্টেম",
+ "skip": "মূল বিষয়বস্তুতে যান",
+ "theme.day": "Day",
+ "theme.label": "থিম",
+ "theme.plain": "Plain",
+ "theme.signal": "Signal",
+ "title": "Fiesta: একটি স্টাইলশিটে পুরো ডিজাইন সিস্টেম",
+ "why.a11y.body": "WCAG অনুযায়ী কনট্রাস্ট যাচাই, আসল ফোকাস রিং, হাই-কনট্রাস্ট মোড ও প্রিন্ট সবই সামলানো।",
+ "why.a11y.title": "ডিফল্টেই অ্যাক্সেসযোগ্য",
+ "why.attrs.body": "যা, তা-ই পড়া যায়। ক্লাসের জঞ্জাল নেই।",
+ "why.attrs.title": "সাদামাটা HTML অ্যাট্রিবিউট",
+ "why.dark.body": "সিস্টেম অনুসরণ করে, বা আপনার যোগ করা সুইচ। প্রতিটি রং দুই মোডেই যাচাই করা।",
+ "why.dark.title": "লাইট ও ডার্ক, বিল্ট-ইন",
+ "why.depth.body": "বোতাম চাপ খায়, কার্ডে আলো পড়ে, আর আলো আপনার পয়েন্টারকে অনুসরণ করে।",
+ "why.depth.title": "জীবন্ত গভীরতা",
+ "why.link.body": "একটি স্টাইলশিট ট্যাগ পেস্ট করুন। যেকোনো পেজে, যেকোনো ফ্রেমওয়ার্কে বা ফ্রেমওয়ার্ক ছাড়াই কাজ করে।",
+ "why.link.title": "একটি লিংক, কোনো বিল্ড নেই",
+ "why.rtl.body": "আরবি, হিব্রু ও অন্য সব লিপি বাড়তি CSS ছাড়াই ঠিকঠাক সাজে।",
+ "why.rtl.title": "ডান-থেকে-বাম প্রস্তুত"
+}
diff --git a/site/landing/strings/en.json b/site/landing/strings/en.json
new file mode 100644
index 0000000..b555bd2
--- /dev/null
+++ b/site/landing/strings/en.json
@@ -0,0 +1,88 @@
+{
+ "copied": "Copied",
+ "copy": "Copy",
+ "copy.failed": "Couldn't copy. The link tag is selected, so you can copy it yourself.",
+ "cta.see": "See the design system",
+ "cta.themes": "View themes",
+ "description": "Fiesta is a design system you add with one stylesheet link. Polished, accessible components in light and dark, in eleven languages, right to left too. No build step, under 25KiB gzipped.",
+ "foot.carlos.framework": "CARLOS framework",
+ "foot.carlos.platform": "CARLOS platform",
+ "foot.carlos.start": "Get started with CARLOS",
+ "foot.docs": "Docs",
+ "foot.eleven": "The Eleven Factors",
+ "foot.letters": "The six letters",
+ "foot.licence": "Open source",
+ "foot.principles": "Principles",
+ "foot.source": "Source",
+ "foot.tagline": "The design system from Rastrillo, the web framework of the CARLOS project.",
+ "foot.trust": "Trust",
+ "foot.version": "Version",
+ "headline": "Celebrate your new design system",
+ "install": "One stylesheet and done. JS optional. <25KiB gzipped.",
+ "lang.label": "Language",
+ "lede": "Polished, accessible, multi-lingual, localised components for everyone.",
+ "nav.design": "Design system",
+ "nav.label": "Main",
+ "nav.start": "Get started",
+ "nav.themes": "Themes",
+ "sample.cancel": "Cancel",
+ "sample.coming": "Coming",
+ "sample.courses": "Courses",
+ "sample.desserts": "Desserts",
+ "sample.dish.glutenfree": "Gluten-free",
+ "sample.dish.nuts": "Contains nuts",
+ "sample.dish.vegetarian": "Vegetarian",
+ "sample.dishes": "Dishes",
+ "sample.email": "Email me each reply",
+ "sample.export": "Export list",
+ "sample.fade": "Fade between songs",
+ "sample.guest.noreply": "No reply yet",
+ "sample.guest.plusone": "Bringing a plus one",
+ "sample.guest.vegetarian": "Vegetarian",
+ "sample.guests": "Guests",
+ "sample.invite": "Invite guests",
+ "sample.invited": "Invited",
+ "sample.label": "A sample app built with Fiesta",
+ "sample.mains": "Mains",
+ "sample.menu": "Menu",
+ "sample.music": "Music",
+ "sample.nav.label": "Party planner",
+ "sample.next": "Next up",
+ "sample.next.body": "Reminders go out on Friday. Three guests still need a reply.",
+ "sample.overview": "Overview",
+ "sample.partyname": "Party name",
+ "sample.playing": "Playing",
+ "sample.public": "Public RSVP page",
+ "sample.reminders": "Send reminders the day before",
+ "sample.save": "Save",
+ "sample.saved": "Saved. This sample has no server, so nothing was stored.",
+ "sample.search": "Search guests",
+ "sample.searched": "Searched. This sample has no server, so the list stays as it is.",
+ "sample.settings": "Settings",
+ "sample.shuffle": "Shuffle",
+ "sample.songs": "Songs",
+ "sample.starters": "Starters",
+ "sample.timezone": "Time zone",
+ "scheme.dark": "Dark",
+ "scheme.label": "Colour scheme",
+ "scheme.light": "Light",
+ "scheme.system": "System",
+ "skip": "Skip to content",
+ "theme.day": "Day",
+ "theme.label": "Theme",
+ "theme.plain": "Plain",
+ "theme.signal": "Signal",
+ "title": "Fiesta: a design system in one stylesheet",
+ "why.a11y.body": "Contrast checked to WCAG, real focus rings, high-contrast mode and print handled.",
+ "why.a11y.title": "Accessible by default",
+ "why.attrs.body": "reads like what it is. No class soup.",
+ "why.attrs.title": "Plain HTML attributes",
+ "why.dark.body": "Follows the system, or a switch you add. Every colour is checked in both.",
+ "why.dark.title": "Light and dark, built in",
+ "why.depth.body": "Buttons press in, cards catch the light, and the light follows your pointer.",
+ "why.depth.title": "Depth that feels alive",
+ "why.link.body": "Paste a stylesheet tag. Works in any page, any framework, or none.",
+ "why.link.title": "One link, no build",
+ "why.rtl.body": "Arabic, Hebrew and every other script lay out correctly with no extra CSS.",
+ "why.rtl.title": "Right-to-left ready"
+}
diff --git a/site/landing/strings/es.json b/site/landing/strings/es.json
new file mode 100644
index 0000000..b7644b5
--- /dev/null
+++ b/site/landing/strings/es.json
@@ -0,0 +1,88 @@
+{
+ "copied": "Copiado",
+ "copy": "Copiar",
+ "copy.failed": "No se pudo copiar. La etiqueta del enlace está seleccionada, así que puedes copiarla tú mismo.",
+ "cta.see": "Ver el sistema de diseño",
+ "cta.themes": "Ver los temas",
+ "description": "Fiesta es un sistema de diseño que añades con un enlace a una hoja de estilos. Componentes pulidos y accesibles, en claro y oscuro, en once idiomas, también de derecha a izquierda. Sin compilar, menos de 25KiB comprimido con gzip.",
+ "foot.carlos.framework": "Framework CARLOS",
+ "foot.carlos.platform": "Plataforma CARLOS",
+ "foot.carlos.start": "Empieza con CARLOS",
+ "foot.docs": "Documentación",
+ "foot.eleven": "The Eleven Factors",
+ "foot.letters": "Las seis letras",
+ "foot.licence": "Código abierto",
+ "foot.principles": "Principios",
+ "foot.source": "Código fuente",
+ "foot.tagline": "El sistema de diseño de Rastrillo, el framework web del proyecto CARLOS.",
+ "foot.trust": "Confianza",
+ "foot.version": "Versión",
+ "headline": "Celebra tu nuevo sistema de diseño",
+ "install": "Una hoja de estilos y listo. JS opcional. <25KiB comprimido con gzip.",
+ "lang.label": "Idioma",
+ "lede": "Componentes pulidos, accesibles, multilingües y localizados para todo el mundo.",
+ "nav.design": "Sistema de diseño",
+ "nav.label": "Principal",
+ "nav.start": "Empezar",
+ "nav.themes": "Temas",
+ "sample.cancel": "Cancelar",
+ "sample.coming": "Confirmado",
+ "sample.courses": "Platos del menú",
+ "sample.desserts": "Postres",
+ "sample.dish.glutenfree": "Sin gluten",
+ "sample.dish.nuts": "Contiene frutos secos",
+ "sample.dish.vegetarian": "Vegetariano",
+ "sample.dishes": "Platos",
+ "sample.email": "Avisarme por correo de cada respuesta",
+ "sample.export": "Exportar lista",
+ "sample.fade": "Fundir entre canciones",
+ "sample.guest.noreply": "Sin respuesta todavía",
+ "sample.guest.plusone": "Viene con acompañante",
+ "sample.guest.vegetarian": "Vegetariana",
+ "sample.guests": "Invitados",
+ "sample.invite": "Añadir invitados",
+ "sample.invited": "Invitado",
+ "sample.label": "Una aplicación de ejemplo hecha con Fiesta",
+ "sample.mains": "Principales",
+ "sample.menu": "Menú",
+ "sample.music": "Música",
+ "sample.nav.label": "Planificador de fiestas",
+ "sample.next": "Lo siguiente",
+ "sample.next.body": "Los recordatorios salen el viernes. Tres invitados aún no han respondido.",
+ "sample.overview": "Resumen",
+ "sample.partyname": "Nombre de la fiesta",
+ "sample.playing": "Sonando",
+ "sample.public": "Página de confirmación pública",
+ "sample.reminders": "Enviar recordatorios el día anterior",
+ "sample.save": "Guardar",
+ "sample.saved": "Guardado. Este ejemplo no tiene servidor, así que no se ha almacenado nada.",
+ "sample.search": "Buscar invitados",
+ "sample.searched": "Búsqueda hecha. Este ejemplo no tiene servidor, así que la lista se queda como está.",
+ "sample.settings": "Ajustes",
+ "sample.shuffle": "Aleatorio",
+ "sample.songs": "Canciones",
+ "sample.starters": "Entrantes",
+ "sample.timezone": "Zona horaria",
+ "scheme.dark": "Oscuro",
+ "scheme.label": "Esquema de color",
+ "scheme.light": "Claro",
+ "scheme.system": "Sistema",
+ "skip": "Saltar al contenido",
+ "theme.day": "Day",
+ "theme.label": "Tema",
+ "theme.plain": "Plain",
+ "theme.signal": "Signal",
+ "title": "Fiesta: un sistema de diseño en una sola hoja de estilos",
+ "why.a11y.body": "Contraste verificado según WCAG, anillos de foco reales, modo de alto contraste e impresión resueltos.",
+ "why.a11y.title": "Accesible por defecto",
+ "why.attrs.body": "se lee como lo que es. Sin sopa de clases.",
+ "why.attrs.title": "Atributos HTML sin más",
+ "why.dark.body": "Sigue al sistema o a un interruptor que añadas. Cada color está comprobado en ambos.",
+ "why.dark.title": "Claro y oscuro, de serie",
+ "why.depth.body": "Los botones se hunden, las tarjetas captan la luz y la luz sigue a tu puntero.",
+ "why.depth.title": "Profundidad con vida",
+ "why.link.body": "Pega una etiqueta de hoja de estilos. Funciona en cualquier página, con cualquier framework o sin ninguno.",
+ "why.link.title": "Un enlace, sin compilar",
+ "why.rtl.body": "El árabe, el hebreo y cualquier otra escritura se maquetan bien sin CSS adicional.",
+ "why.rtl.title": "Preparado para derecha a izquierda"
+}
diff --git a/site/landing/strings/ga.json b/site/landing/strings/ga.json
new file mode 100644
index 0000000..9ae27dd
--- /dev/null
+++ b/site/landing/strings/ga.json
@@ -0,0 +1,88 @@
+{
+ "copied": "Cóipeáilte",
+ "copy": "Cóipeáil",
+ "copy.failed": "Níorbh fhéidir cóipeáil. Tá clib an naisc roghnaithe, mar sin is féidir leat í a chóipeáil tú féin.",
+ "cta.see": "Féach ar an gcóras deartha",
+ "cta.themes": "Féach ar na téamaí",
+ "description": "Is córas deartha é Fiesta a chuireann tú leis le nasc stílbhileoige amháin. Comhpháirteanna snasta, inrochtana, i solas agus i ndorchadas, in aon teanga dhéag, ó dheis go clé freisin. Gan céim tógála, faoi bhun 25KiB gzip-áilte.",
+ "foot.carlos.framework": "Creatlach CARLOS",
+ "foot.carlos.platform": "Ardán CARLOS",
+ "foot.carlos.start": "Tosaigh le CARLOS",
+ "foot.docs": "Doiciméid",
+ "foot.eleven": "The Eleven Factors",
+ "foot.letters": "Na sé litir",
+ "foot.licence": "Foinse oscailte",
+ "foot.principles": "Prionsabail",
+ "foot.source": "Foinse",
+ "foot.tagline": "An córas deartha ó Rastrillo, creatlach gréasáin thionscadal CARLOS.",
+ "foot.trust": "Muinín",
+ "foot.version": "Leagan",
+ "headline": "Ceiliúir do chóras deartha nua",
+ "install": "Stílbhileog amháin agus sin é. JS roghnach. <25KiB gzip-áilte.",
+ "lang.label": "Teanga",
+ "lede": "Comhpháirteanna snasta, inrochtana, ilteangacha, logánaithe do chách.",
+ "nav.design": "Córas deartha",
+ "nav.label": "Príomhnaisc",
+ "nav.start": "Tosaigh",
+ "nav.themes": "Téamaí",
+ "sample.cancel": "Cealaigh",
+ "sample.coming": "Ag teacht",
+ "sample.courses": "Cúrsaí",
+ "sample.desserts": "Milseoga",
+ "sample.dish.glutenfree": "Saor ó ghlútan",
+ "sample.dish.nuts": "Cnónna ann",
+ "sample.dish.vegetarian": "Veigeatórach",
+ "sample.dishes": "Miasa",
+ "sample.email": "Cuir ríomhphost chugam le gach freagra",
+ "sample.export": "Easpórtáil an liosta",
+ "sample.fade": "Céimnigh idir amhráin",
+ "sample.guest.noreply": "Gan freagra fós",
+ "sample.guest.plusone": "Duine eile ag teacht leis",
+ "sample.guest.vegetarian": "Veigeatóir",
+ "sample.guests": "Aíonna",
+ "sample.invite": "Tabhair cuireadh d’aíonna",
+ "sample.invited": "Cuireadh tugtha",
+ "sample.label": "Aip shamplach a tógadh le Fiesta",
+ "sample.mains": "Príomhchúrsaí",
+ "sample.menu": "Biachlár",
+ "sample.music": "Ceol",
+ "sample.nav.label": "Pleanálaí cóisire",
+ "sample.next": "Ar aghaidh",
+ "sample.next.body": "Seoltar na meabhrúcháin Dé hAoine. Tá triúr aíonna fós le freagra a thabhairt.",
+ "sample.overview": "Forbhreathnú",
+ "sample.partyname": "Ainm na cóisire",
+ "sample.playing": "Á sheinm",
+ "sample.public": "Leathanach RSVP poiblí",
+ "sample.reminders": "Seol meabhrúcháin an lá roimh ré",
+ "sample.save": "Sábháil",
+ "sample.saved": "Sábháilte. Níl aon fhreastalaí ag an sampla seo, mar sin níor stóráladh aon rud.",
+ "sample.search": "Cuardaigh aíonna",
+ "sample.searched": "Cuardaithe. Níl aon fhreastalaí ag an sampla seo, mar sin fanann an liosta mar atá.",
+ "sample.settings": "Socruithe",
+ "sample.shuffle": "Suaitheadh",
+ "sample.songs": "Amhráin",
+ "sample.starters": "Cúrsaí tosaigh",
+ "sample.timezone": "Crios ama",
+ "scheme.dark": "Dorcha",
+ "scheme.label": "Scéim dathanna",
+ "scheme.light": "Sorcha",
+ "scheme.system": "Córas",
+ "skip": "Léim go dtí an t-ábhar",
+ "theme.day": "Day",
+ "theme.label": "Téama",
+ "theme.plain": "Plain",
+ "theme.signal": "Signal",
+ "title": "Fiesta: córas deartha in aon stílbhileog amháin",
+ "why.a11y.body": "Codarsnacht seiceáilte de réir WCAG, fáinní fócais cearta, mód ardchodarsnachta agus priontáil láimhseáilte.",
+ "why.a11y.title": "Inrochtana de réir réamhshocraithe",
+ "why.attrs.body": "léann sé mar atá sé. Gan anraith ranganna.",
+ "why.attrs.title": "Tréithe HTML simplí",
+ "why.dark.body": "Leanann sé an córas, nó lasc a chuireann tú leis. Seiceáiltear gach dath sa dá mhód.",
+ "why.dark.title": "Solas agus dorchadas, ionsuite",
+ "why.depth.body": "Brúnn cnaipí isteach, gabhann cártaí an solas, agus leanann an solas do phointeoir.",
+ "why.depth.title": "Doimhneacht atá beo",
+ "why.link.body": "Greamaigh clib stílbhileoige. Oibríonn sé in aon leathanach, le haon chreatlach, nó gan ceann ar bith.",
+ "why.link.title": "Nasc amháin, gan tógáil",
+ "why.rtl.body": "Leagtar amach an Araibis, an Eabhrais agus gach script eile i gceart gan CSS breise.",
+ "why.rtl.title": "Réidh do dheas-go-clé"
+}
diff --git a/site/landing/strings/hi.json b/site/landing/strings/hi.json
new file mode 100644
index 0000000..06125d1
--- /dev/null
+++ b/site/landing/strings/hi.json
@@ -0,0 +1,88 @@
+{
+ "copied": "कॉपी हो गया",
+ "copy": "कॉपी करें",
+ "copy.failed": "कॉपी नहीं हो सका। लिंक टैग चुना हुआ है, इसलिए आप उसे खुद कॉपी कर सकते हैं।",
+ "cta.see": "डिज़ाइन सिस्टम देखें",
+ "cta.themes": "थीम देखें",
+ "description": "Fiesta एक ऐसा डिज़ाइन सिस्टम है जिसे आप एक स्टाइलशीट लिंक से जोड़ देते हैं। सुघड़, सुलभ कंपोनेंट, लाइट और डार्क दोनों में, ग्यारह भाषाओं में, दाएँ-से-बाएँ भी। कोई बिल्ड स्टेप नहीं, gzip के बाद 25KiB से कम।",
+ "foot.carlos.framework": "CARLOS फ़्रेमवर्क",
+ "foot.carlos.platform": "CARLOS प्लेटफ़ॉर्म",
+ "foot.carlos.start": "CARLOS के साथ शुरू करें",
+ "foot.docs": "दस्तावेज़",
+ "foot.eleven": "The Eleven Factors",
+ "foot.letters": "छह अक्षर",
+ "foot.licence": "ओपन सोर्स",
+ "foot.principles": "सिद्धांत",
+ "foot.source": "सोर्स",
+ "foot.tagline": "Rastrillo का डिज़ाइन सिस्टम, जो CARLOS परियोजना का वेब फ़्रेमवर्क है।",
+ "foot.trust": "भरोसा",
+ "foot.version": "संस्करण",
+ "headline": "अपने नए डिज़ाइन सिस्टम का जश्न मनाएँ",
+ "install": "एक स्टाइलशीट और बस। JS वैकल्पिक। gzip के बाद <25KiB।",
+ "lang.label": "भाषा",
+ "lede": "सबके लिए सुघड़, सुलभ, बहुभाषी और स्थानीयकृत कंपोनेंट।",
+ "nav.design": "डिज़ाइन सिस्टम",
+ "nav.label": "मुख्य",
+ "nav.start": "शुरू करें",
+ "nav.themes": "थीम",
+ "sample.cancel": "रद्द करें",
+ "sample.coming": "आ रहे हैं",
+ "sample.courses": "कोर्स",
+ "sample.desserts": "मिठाई",
+ "sample.dish.glutenfree": "ग्लूटेन-मुक्त",
+ "sample.dish.nuts": "इसमें मेवे हैं",
+ "sample.dish.vegetarian": "शाकाहारी",
+ "sample.dishes": "व्यंजन",
+ "sample.email": "हर जवाब पर मुझे ईमेल करें",
+ "sample.export": "सूची एक्सपोर्ट करें",
+ "sample.fade": "गानों के बीच फ़ेड",
+ "sample.guest.noreply": "अभी जवाब नहीं",
+ "sample.guest.plusone": "साथ में एक और आ रहे हैं",
+ "sample.guest.vegetarian": "शाकाहारी",
+ "sample.guests": "मेहमान",
+ "sample.invite": "मेहमान आमंत्रित करें",
+ "sample.invited": "आमंत्रित",
+ "sample.label": "Fiesta से बना एक नमूना ऐप",
+ "sample.mains": "मुख्य व्यंजन",
+ "sample.menu": "मेन्यू",
+ "sample.music": "संगीत",
+ "sample.nav.label": "पार्टी प्लानर",
+ "sample.next": "आगे",
+ "sample.next.body": "रिमाइंडर शुक्रवार को जाएँगे। तीन मेहमानों का जवाब अभी बाकी है।",
+ "sample.overview": "अवलोकन",
+ "sample.partyname": "पार्टी का नाम",
+ "sample.playing": "चल रहा है",
+ "sample.public": "सार्वजनिक RSVP पेज",
+ "sample.reminders": "एक दिन पहले रिमाइंडर भेजें",
+ "sample.save": "सहेजें",
+ "sample.saved": "सहेज लिया। इस नमूने में कोई सर्वर नहीं है, इसलिए कुछ भी संग्रहीत नहीं हुआ।",
+ "sample.search": "मेहमान खोजें",
+ "sample.searched": "खोज हो गई। इस नमूने में कोई सर्वर नहीं है, इसलिए सूची जैसी है वैसी ही रहती है।",
+ "sample.settings": "सेटिंग्स",
+ "sample.shuffle": "शफ़ल",
+ "sample.songs": "गाने",
+ "sample.starters": "स्टार्टर",
+ "sample.timezone": "समय क्षेत्र",
+ "scheme.dark": "गहरा",
+ "scheme.label": "रंग योजना",
+ "scheme.light": "हल्का",
+ "scheme.system": "सिस्टम",
+ "skip": "सीधे सामग्री पर जाएँ",
+ "theme.day": "Day",
+ "theme.label": "थीम",
+ "theme.plain": "Plain",
+ "theme.signal": "Signal",
+ "title": "Fiesta: एक स्टाइलशीट में पूरा डिज़ाइन सिस्टम",
+ "why.a11y.body": "WCAG के अनुसार कंट्रास्ट जाँच, असली फ़ोकस रिंग, हाई-कंट्रास्ट मोड और प्रिंट, सब संभाला हुआ।",
+ "why.a11y.title": "डिफ़ॉल्ट रूप से सुलभ",
+ "why.attrs.body": "जो है, वही पढ़ने में आता है। क्लास का घालमेल नहीं।",
+ "why.attrs.title": "सादे HTML एट्रिब्यूट",
+ "why.dark.body": "सिस्टम का अनुसरण करता है, या आपके जोड़े स्विच का। हर रंग दोनों में जाँचा गया है।",
+ "why.dark.title": "लाइट और डार्क, पहले से शामिल",
+ "why.depth.body": "बटन दबते हैं, कार्ड रोशनी पकड़ते हैं, और रोशनी आपके पॉइंटर के पीछे चलती है।",
+ "why.depth.title": "गहराई जो ज़िंदा लगे",
+ "why.link.body": "एक स्टाइलशीट टैग पेस्ट करें। किसी भी पेज, किसी भी फ़्रेमवर्क या बिना फ़्रेमवर्क के चलता है।",
+ "why.link.title": "एक लिंक, कोई बिल्ड नहीं",
+ "why.rtl.body": "अरबी, हिब्रू और हर दूसरी लिपि बिना अतिरिक्त CSS के सही ढंग से सजती है।",
+ "why.rtl.title": "दाएँ-से-बाएँ के लिए तैयार"
+}
diff --git a/site/landing/strings/ja.json b/site/landing/strings/ja.json
new file mode 100644
index 0000000..6513dd5
--- /dev/null
+++ b/site/landing/strings/ja.json
@@ -0,0 +1,88 @@
+{
+ "copied": "コピー済み",
+ "copy": "コピー",
+ "copy.failed": "コピーできませんでした。リンクタグは選択されているので、ご自身でコピーできます。",
+ "cta.see": "デザインシステムを見る",
+ "cta.themes": "テーマを見る",
+ "description": "Fiestaは、スタイルシートのリンク1本で追加できるデザインシステムです。洗練されたアクセシブルなコンポーネントをライトとダークの両方で、11言語で、右から左に書く言語にも対応。ビルド不要、gzip後25KiB未満。",
+ "foot.carlos.framework": "CARLOSフレームワーク",
+ "foot.carlos.platform": "CARLOSプラットフォーム",
+ "foot.carlos.start": "CARLOSをはじめる",
+ "foot.docs": "ドキュメント",
+ "foot.eleven": "The Eleven Factors",
+ "foot.letters": "6つの文字",
+ "foot.licence": "オープンソース",
+ "foot.principles": "原則",
+ "foot.source": "ソースコード",
+ "foot.tagline": "CARLOSプロジェクトのウェブフレームワークRastrilloから生まれたデザインシステム。",
+ "foot.trust": "信頼",
+ "foot.version": "バージョン",
+ "headline": "新しいデザインシステムを祝おう",
+ "install": "スタイルシート1枚で完了。JSは任意。gzip後<25KiB。",
+ "lang.label": "言語",
+ "lede": "洗練され、アクセシブルで、多言語対応。みんなのためのコンポーネントです。",
+ "nav.design": "デザインシステム",
+ "nav.label": "メイン",
+ "nav.start": "はじめる",
+ "nav.themes": "テーマ",
+ "sample.cancel": "キャンセル",
+ "sample.coming": "出席",
+ "sample.courses": "コース",
+ "sample.desserts": "デザート",
+ "sample.dish.glutenfree": "グルテンフリー",
+ "sample.dish.nuts": "ナッツ使用",
+ "sample.dish.vegetarian": "ベジタリアン",
+ "sample.dishes": "料理",
+ "sample.email": "返信ごとにメールで通知",
+ "sample.export": "リストを書き出す",
+ "sample.fade": "曲間をフェード",
+ "sample.guest.noreply": "未返信",
+ "sample.guest.plusone": "同伴者1名",
+ "sample.guest.vegetarian": "ベジタリアン",
+ "sample.guests": "ゲスト",
+ "sample.invite": "ゲストを招待",
+ "sample.invited": "招待済み",
+ "sample.label": "Fiestaで作ったサンプルアプリ",
+ "sample.mains": "メイン",
+ "sample.menu": "メニュー",
+ "sample.music": "音楽",
+ "sample.nav.label": "パーティー企画",
+ "sample.next": "次の予定",
+ "sample.next.body": "リマインダーは金曜日に送信。3名のゲストが未返信です。",
+ "sample.overview": "概要",
+ "sample.partyname": "パーティー名",
+ "sample.playing": "再生中",
+ "sample.public": "公開RSVPページ",
+ "sample.reminders": "前日にリマインダーを送る",
+ "sample.save": "保存",
+ "sample.saved": "保存しました。このサンプルにはサーバーがないため、何も保存されていません。",
+ "sample.search": "ゲストを検索",
+ "sample.searched": "検索しました。このサンプルにはサーバーがないため、リストはそのままです。",
+ "sample.settings": "設定",
+ "sample.shuffle": "シャッフル",
+ "sample.songs": "曲",
+ "sample.starters": "前菜",
+ "sample.timezone": "タイムゾーン",
+ "scheme.dark": "ダーク",
+ "scheme.label": "配色",
+ "scheme.light": "ライト",
+ "scheme.system": "システムに合わせる",
+ "skip": "本文へ移動",
+ "theme.day": "Day",
+ "theme.label": "テーマ",
+ "theme.plain": "Plain",
+ "theme.signal": "Signal",
+ "title": "Fiesta:スタイルシート1枚で使えるデザインシステム",
+ "why.a11y.body": "WCAG基準のコントラスト、本物のフォーカスリング、ハイコントラストモードと印刷にも対応。",
+ "why.a11y.title": "標準でアクセシブル",
+ "why.attrs.body": "は見たままの意味。クラスのごった煮はありません。",
+ "why.attrs.title": "素のHTML属性",
+ "why.dark.body": "システム設定に従うか、追加したスイッチで切り替え。すべての色を両方で確認済み。",
+ "why.dark.title": "ライトとダーク、標準装備",
+ "why.depth.body": "ボタンは沈み、カードは光を受け、光はポインターを追いかけます。",
+ "why.depth.title": "生きているような奥行き",
+ "why.link.body": "スタイルシートのタグを貼るだけ。どんなページでも、どんなフレームワークでも、フレームワークなしでも動きます。",
+ "why.link.title": "リンク1本、ビルド不要",
+ "why.rtl.body": "アラビア語、ヘブライ語、その他あらゆる文字が追加CSSなしで正しく並びます。",
+ "why.rtl.title": "右から左にも対応"
+}
diff --git a/site/landing/strings/pt-PT.json b/site/landing/strings/pt-PT.json
new file mode 100644
index 0000000..f410910
--- /dev/null
+++ b/site/landing/strings/pt-PT.json
@@ -0,0 +1,88 @@
+{
+ "copied": "Copiado",
+ "copy": "Copiar",
+ "copy.failed": "Não foi possível copiar. A etiqueta da ligação está selecionada, por isso pode copiá-la você mesmo.",
+ "cta.see": "Ver o sistema de design",
+ "cta.themes": "Ver os temas",
+ "description": "O Fiesta é um sistema de design que adiciona com uma ligação a uma folha de estilos. Componentes polidos e acessíveis, em claro e escuro, em onze idiomas, também da direita para a esquerda. Sem build, menos de 25KiB comprimido com gzip.",
+ "foot.carlos.framework": "Framework CARLOS",
+ "foot.carlos.platform": "Plataforma CARLOS",
+ "foot.carlos.start": "Comece com o CARLOS",
+ "foot.docs": "Documentação",
+ "foot.eleven": "The Eleven Factors",
+ "foot.letters": "As seis letras",
+ "foot.licence": "Código aberto",
+ "foot.principles": "Princípios",
+ "foot.source": "Código-fonte",
+ "foot.tagline": "O sistema de design do Rastrillo, a framework web do projeto CARLOS.",
+ "foot.trust": "Confiança",
+ "foot.version": "Versão",
+ "headline": "Celebre o seu novo sistema de design",
+ "install": "Uma folha de estilos e está feito. JS opcional. <25KiB comprimido com gzip.",
+ "lang.label": "Idioma",
+ "lede": "Componentes polidos, acessíveis, multilingues e localizados para toda a gente.",
+ "nav.design": "Sistema de design",
+ "nav.label": "Principal",
+ "nav.start": "Começar",
+ "nav.themes": "Temas",
+ "sample.cancel": "Cancelar",
+ "sample.coming": "Confirmado",
+ "sample.courses": "Pratos da ementa",
+ "sample.desserts": "Sobremesas",
+ "sample.dish.glutenfree": "Sem glúten",
+ "sample.dish.nuts": "Contém frutos secos",
+ "sample.dish.vegetarian": "Vegetariano",
+ "sample.dishes": "Pratos",
+ "sample.email": "Enviar-me um e-mail por cada resposta",
+ "sample.export": "Exportar lista",
+ "sample.fade": "Fundir entre músicas",
+ "sample.guest.noreply": "Ainda sem resposta",
+ "sample.guest.plusone": "Traz acompanhante",
+ "sample.guest.vegetarian": "Vegetariana",
+ "sample.guests": "Convidados",
+ "sample.invite": "Convidar pessoas",
+ "sample.invited": "Convidado",
+ "sample.label": "Uma aplicação de exemplo feita com o Fiesta",
+ "sample.mains": "Pratos principais",
+ "sample.menu": "Ementa",
+ "sample.music": "Música",
+ "sample.nav.label": "Planeador de festas",
+ "sample.next": "A seguir",
+ "sample.next.body": "Os lembretes saem na sexta-feira. Três convidados ainda não responderam.",
+ "sample.overview": "Visão geral",
+ "sample.partyname": "Nome da festa",
+ "sample.playing": "A tocar",
+ "sample.public": "Página de RSVP pública",
+ "sample.reminders": "Enviar lembretes no dia anterior",
+ "sample.save": "Guardar",
+ "sample.saved": "Guardado. Este exemplo não tem servidor, por isso nada foi armazenado.",
+ "sample.search": "Pesquisar convidados",
+ "sample.searched": "Pesquisa feita. Este exemplo não tem servidor, por isso a lista fica como está.",
+ "sample.settings": "Definições",
+ "sample.shuffle": "Aleatório",
+ "sample.songs": "Músicas",
+ "sample.starters": "Entradas",
+ "sample.timezone": "Fuso horário",
+ "scheme.dark": "Escuro",
+ "scheme.label": "Esquema de cores",
+ "scheme.light": "Claro",
+ "scheme.system": "Sistema",
+ "skip": "Saltar para o conteúdo",
+ "theme.day": "Day",
+ "theme.label": "Tema",
+ "theme.plain": "Plain",
+ "theme.signal": "Signal",
+ "title": "Fiesta: um sistema de design numa única folha de estilos",
+ "why.a11y.body": "Contraste verificado segundo as WCAG, anéis de foco a sério, modo de alto contraste e impressão tratados.",
+ "why.a11y.title": "Acessível por omissão",
+ "why.attrs.body": "lê-se como aquilo que é. Sem sopa de classes.",
+ "why.attrs.title": "Atributos HTML simples",
+ "why.dark.body": "Segue o sistema ou um interruptor que adicione. Todas as cores são verificadas em ambos.",
+ "why.dark.title": "Claro e escuro, de origem",
+ "why.depth.body": "Os botões afundam, os cartões apanham a luz e a luz segue o seu ponteiro.",
+ "why.depth.title": "Profundidade com vida",
+ "why.link.body": "Cole uma etiqueta de folha de estilos. Funciona em qualquer página, com qualquer framework ou sem nenhuma.",
+ "why.link.title": "Uma ligação, sem build",
+ "why.rtl.body": "Árabe, hebraico e todas as outras escritas ficam bem dispostas sem CSS adicional.",
+ "why.rtl.title": "Pronto para direita-para-esquerda"
+}
diff --git a/site/landing/strings/ru.json b/site/landing/strings/ru.json
new file mode 100644
index 0000000..c2662a6
--- /dev/null
+++ b/site/landing/strings/ru.json
@@ -0,0 +1,88 @@
+{
+ "copied": "Скопировано",
+ "copy": "Копировать",
+ "copy.failed": "Не удалось скопировать. Тег ссылки выделен, так что вы можете скопировать его сами.",
+ "cta.see": "Смотреть дизайн-систему",
+ "cta.themes": "Смотреть темы",
+ "description": "Дизайн-система Fiesta подключается одной ссылкой на таблицу стилей. Отточенные, доступные компоненты в светлой и тёмной темах, на одиннадцати языках, в том числе справа налево. Без сборки, меньше 25KiB в gzip.",
+ "foot.carlos.framework": "Фреймворк CARLOS",
+ "foot.carlos.platform": "Платформа CARLOS",
+ "foot.carlos.start": "Начать с CARLOS",
+ "foot.docs": "Документация",
+ "foot.eleven": "The Eleven Factors",
+ "foot.letters": "Шесть букв",
+ "foot.licence": "Открытый код",
+ "foot.principles": "Принципы",
+ "foot.source": "Исходный код",
+ "foot.tagline": "Дизайн-система от Rastrillo, веб-фреймворка проекта CARLOS.",
+ "foot.trust": "Доверие",
+ "foot.version": "Версия",
+ "headline": "Отпразднуйте новую дизайн-систему",
+ "install": "Одна таблица стилей, и готово. JS по желанию. <25KiB в gzip.",
+ "lang.label": "Язык",
+ "lede": "Отточенные, доступные, многоязычные и локализованные компоненты для всех.",
+ "nav.design": "Дизайн-система",
+ "nav.label": "Основная",
+ "nav.start": "Начать",
+ "nav.themes": "Темы",
+ "sample.cancel": "Отмена",
+ "sample.coming": "Придёт",
+ "sample.courses": "Разделы меню",
+ "sample.desserts": "Десерты",
+ "sample.dish.glutenfree": "Без глютена",
+ "sample.dish.nuts": "Содержит орехи",
+ "sample.dish.vegetarian": "Вегетарианское",
+ "sample.dishes": "Блюда",
+ "sample.email": "Писать мне о каждом ответе",
+ "sample.export": "Экспортировать список",
+ "sample.fade": "Плавный переход между песнями",
+ "sample.guest.noreply": "Пока без ответа",
+ "sample.guest.plusone": "Придёт с +1",
+ "sample.guest.vegetarian": "Вегетарианка",
+ "sample.guests": "Гости",
+ "sample.invite": "Пригласить гостей",
+ "sample.invited": "Приглашён",
+ "sample.label": "Пример приложения на Fiesta",
+ "sample.mains": "Основные",
+ "sample.menu": "Меню",
+ "sample.music": "Музыка",
+ "sample.nav.label": "Планировщик праздника",
+ "sample.next": "Дальше",
+ "sample.next.body": "Напоминания уйдут в пятницу. Трое гостей ещё не ответили.",
+ "sample.overview": "Обзор",
+ "sample.partyname": "Название праздника",
+ "sample.playing": "Играет",
+ "sample.public": "Публичная страница ответов",
+ "sample.reminders": "Напомнить за день",
+ "sample.save": "Сохранить",
+ "sample.saved": "Сохранено. У этого примера нет сервера, поэтому ничего не записано.",
+ "sample.search": "Поиск гостей",
+ "sample.searched": "Поиск выполнен. У этого примера нет сервера, поэтому список остаётся как есть.",
+ "sample.settings": "Настройки",
+ "sample.shuffle": "Вперемешку",
+ "sample.songs": "Песни",
+ "sample.starters": "Закуски",
+ "sample.timezone": "Часовой пояс",
+ "scheme.dark": "Тёмная",
+ "scheme.label": "Цветовая схема",
+ "scheme.light": "Светлая",
+ "scheme.system": "Как в системе",
+ "skip": "Перейти к содержимому",
+ "theme.day": "Day",
+ "theme.label": "Тема",
+ "theme.plain": "Plain",
+ "theme.signal": "Signal",
+ "title": "Fiesta: дизайн-система в одной таблице стилей",
+ "why.a11y.body": "Контраст проверен по WCAG, настоящие кольца фокуса, режим высокой контрастности и печать учтены.",
+ "why.a11y.title": "Доступность по умолчанию",
+ "why.attrs.body": "читается как то, что он есть. Никакой каши из классов.",
+ "why.attrs.title": "Простые HTML-атрибуты",
+ "why.dark.body": "Следует за системой или за вашим переключателем. Каждый цвет проверен в обеих.",
+ "why.dark.title": "Светлая и тёмная темы из коробки",
+ "why.depth.body": "Кнопки вдавливаются, карточки ловят свет, а свет следует за курсором.",
+ "why.depth.title": "Живая глубина",
+ "why.link.body": "Вставьте тег таблицы стилей. Работает на любой странице, с любым фреймворком или без него.",
+ "why.link.title": "Одна ссылка, без сборки",
+ "why.rtl.body": "Арабский, иврит и любая другая письменность раскладываются правильно без лишнего CSS.",
+ "why.rtl.title": "Готово к письму справа налево"
+}
diff --git a/site/landing/strings/vi.json b/site/landing/strings/vi.json
new file mode 100644
index 0000000..fc94ae3
--- /dev/null
+++ b/site/landing/strings/vi.json
@@ -0,0 +1,88 @@
+{
+ "copied": "Đã sao chép",
+ "copy": "Sao chép",
+ "copy.failed": "Không sao chép được. Thẻ liên kết đã được chọn, bạn có thể tự sao chép.",
+ "cta.see": "Xem hệ thống thiết kế",
+ "cta.themes": "Xem giao diện",
+ "description": "Fiesta là hệ thống thiết kế bạn thêm vào chỉ bằng một liên kết stylesheet. Thành phần tinh gọn, dễ tiếp cận, ở cả chế độ sáng và tối, mười một ngôn ngữ, kể cả viết từ phải sang trái. Không cần build, dưới 25KiB sau khi gzip.",
+ "foot.carlos.framework": "Khung CARLOS",
+ "foot.carlos.platform": "Nền tảng CARLOS",
+ "foot.carlos.start": "Bắt đầu với CARLOS",
+ "foot.docs": "Tài liệu",
+ "foot.eleven": "The Eleven Factors",
+ "foot.letters": "Sáu chữ cái",
+ "foot.licence": "Mã nguồn mở",
+ "foot.principles": "Nguyên tắc",
+ "foot.source": "Mã nguồn",
+ "foot.tagline": "Hệ thống thiết kế từ Rastrillo, khung web của dự án CARLOS.",
+ "foot.trust": "Tin cậy",
+ "foot.version": "Phiên bản",
+ "headline": "Ăn mừng hệ thống thiết kế mới của bạn",
+ "install": "Một stylesheet là xong. JS tuỳ chọn. <25KiB sau khi gzip.",
+ "lang.label": "Ngôn ngữ",
+ "lede": "Các thành phần tinh gọn, dễ tiếp cận, đa ngôn ngữ và đã bản địa hoá, dành cho mọi người.",
+ "nav.design": "Hệ thống thiết kế",
+ "nav.label": "Chính",
+ "nav.start": "Bắt đầu",
+ "nav.themes": "Giao diện",
+ "sample.cancel": "Hủy",
+ "sample.coming": "Sẽ đến",
+ "sample.courses": "Các món",
+ "sample.desserts": "Tráng miệng",
+ "sample.dish.glutenfree": "Không gluten",
+ "sample.dish.nuts": "Có các loại hạt",
+ "sample.dish.vegetarian": "Món chay",
+ "sample.dishes": "Món ăn",
+ "sample.email": "Gửi email cho tôi mỗi khi có trả lời",
+ "sample.export": "Xuất danh sách",
+ "sample.fade": "Chuyển mềm giữa các bài",
+ "sample.guest.noreply": "Chưa trả lời",
+ "sample.guest.plusone": "Đi cùng một người",
+ "sample.guest.vegetarian": "Ăn chay",
+ "sample.guests": "Khách mời",
+ "sample.invite": "Mời khách",
+ "sample.invited": "Đã mời",
+ "sample.label": "Một ứng dụng mẫu dựng bằng Fiesta",
+ "sample.mains": "Món chính",
+ "sample.menu": "Thực đơn",
+ "sample.music": "Âm nhạc",
+ "sample.nav.label": "Lên kế hoạch tiệc",
+ "sample.next": "Sắp tới",
+ "sample.next.body": "Lời nhắc sẽ gửi vào thứ Sáu. Ba khách vẫn chưa trả lời.",
+ "sample.overview": "Tổng quan",
+ "sample.partyname": "Tên bữa tiệc",
+ "sample.playing": "Đang phát",
+ "sample.public": "Trang RSVP công khai",
+ "sample.reminders": "Gửi lời nhắc trước một ngày",
+ "sample.save": "Lưu",
+ "sample.saved": "Đã lưu. Bản mẫu này không có máy chủ, nên không có gì được lưu lại.",
+ "sample.search": "Tìm khách mời",
+ "sample.searched": "Đã tìm. Bản mẫu này không có máy chủ, nên danh sách vẫn giữ nguyên.",
+ "sample.settings": "Cài đặt",
+ "sample.shuffle": "Phát ngẫu nhiên",
+ "sample.songs": "Bài hát",
+ "sample.starters": "Khai vị",
+ "sample.timezone": "Múi giờ",
+ "scheme.dark": "Tối",
+ "scheme.label": "Bảng màu",
+ "scheme.light": "Sáng",
+ "scheme.system": "Theo hệ thống",
+ "skip": "Chuyển đến nội dung",
+ "theme.day": "Day",
+ "theme.label": "Chủ đề",
+ "theme.plain": "Plain",
+ "theme.signal": "Signal",
+ "title": "Fiesta: hệ thống thiết kế trong một stylesheet",
+ "why.a11y.body": "Độ tương phản đạt WCAG, vòng focus thật, chế độ tương phản cao và bản in đều được lo.",
+ "why.a11y.title": "Dễ tiếp cận mặc định",
+ "why.attrs.body": "đọc lên là hiểu ngay. Không có mớ class lộn xộn.",
+ "why.attrs.title": "Thuộc tính HTML thuần",
+ "why.dark.body": "Theo hệ thống, hoặc theo công tắc bạn thêm vào. Mọi màu đều được kiểm tra ở cả hai chế độ.",
+ "why.dark.title": "Sáng và tối, có sẵn",
+ "why.depth.body": "Nút lún xuống, thẻ bắt sáng, và ánh sáng đi theo con trỏ của bạn.",
+ "why.depth.title": "Chiều sâu như có sự sống",
+ "why.link.body": "Dán thẻ stylesheet vào. Chạy trên mọi trang, với mọi framework hoặc không cần framework.",
+ "why.link.title": "Một liên kết, không cần build",
+ "why.rtl.body": "Tiếng Ả Rập, tiếng Do Thái và mọi hệ chữ khác đều hiển thị đúng mà không cần thêm CSS.",
+ "why.rtl.title": "Sẵn sàng cho chữ viết phải-sang-trái"
+}
diff --git a/site/landing/strings/zh-Hans.json b/site/landing/strings/zh-Hans.json
new file mode 100644
index 0000000..5505175
--- /dev/null
+++ b/site/landing/strings/zh-Hans.json
@@ -0,0 +1,88 @@
+{
+ "copied": "已复制",
+ "copy": "复制",
+ "copy.failed": "无法复制。链接标签已选中,你可以自己复制。",
+ "cta.see": "查看设计系统",
+ "cta.themes": "查看主题",
+ "description": "Fiesta 是一套设计系统,加一个样式表链接就能用。精致、无障碍的组件,浅色与深色皆备,支持十一种语言,也支持从右到左。无需构建,gzip 后不到 25KiB。",
+ "foot.carlos.framework": "CARLOS 框架",
+ "foot.carlos.platform": "CARLOS 平台",
+ "foot.carlos.start": "开始使用 CARLOS",
+ "foot.docs": "文档",
+ "foot.eleven": "The Eleven Factors",
+ "foot.letters": "六个字母",
+ "foot.licence": "开源",
+ "foot.principles": "原则",
+ "foot.source": "源码",
+ "foot.tagline": "来自 Rastrillo 的设计系统,Rastrillo 是 CARLOS 项目的 Web 框架。",
+ "foot.trust": "信任",
+ "foot.version": "版本",
+ "headline": "为你的新设计系统庆祝",
+ "install": "一个样式表,搞定。JS 可选。gzip 后 <25KiB。",
+ "lang.label": "语言",
+ "lede": "精致、无障碍、多语言、已本地化的组件,献给每一个人。",
+ "nav.design": "设计系统",
+ "nav.label": "主要",
+ "nav.start": "开始使用",
+ "nav.themes": "主题",
+ "sample.cancel": "取消",
+ "sample.coming": "出席",
+ "sample.courses": "菜式",
+ "sample.desserts": "甜点",
+ "sample.dish.glutenfree": "无麸质",
+ "sample.dish.nuts": "含坚果",
+ "sample.dish.vegetarian": "素食",
+ "sample.dishes": "菜品",
+ "sample.email": "每条回复都发邮件给我",
+ "sample.export": "导出名单",
+ "sample.fade": "歌曲间淡入淡出",
+ "sample.guest.noreply": "尚未回复",
+ "sample.guest.plusone": "携一位同伴",
+ "sample.guest.vegetarian": "素食",
+ "sample.guests": "宾客",
+ "sample.invite": "邀请宾客",
+ "sample.invited": "已邀请",
+ "sample.label": "用 Fiesta 构建的示例应用",
+ "sample.mains": "主菜",
+ "sample.menu": "菜单",
+ "sample.music": "音乐",
+ "sample.nav.label": "派对策划",
+ "sample.next": "接下来",
+ "sample.next.body": "提醒将在周五发送。还有三位宾客未回复。",
+ "sample.overview": "概览",
+ "sample.partyname": "派对名称",
+ "sample.playing": "播放中",
+ "sample.public": "公开的回复页面",
+ "sample.reminders": "提前一天发送提醒",
+ "sample.save": "保存",
+ "sample.saved": "已保存。这个示例没有服务器,所以什么也没有存储。",
+ "sample.search": "搜索宾客",
+ "sample.searched": "已搜索。这个示例没有服务器,所以名单保持不变。",
+ "sample.settings": "设置",
+ "sample.shuffle": "随机播放",
+ "sample.songs": "歌曲",
+ "sample.starters": "前菜",
+ "sample.timezone": "时区",
+ "scheme.dark": "深色",
+ "scheme.label": "配色方案",
+ "scheme.light": "浅色",
+ "scheme.system": "跟随系统",
+ "skip": "跳到正文",
+ "theme.day": "Day",
+ "theme.label": "主题",
+ "theme.plain": "Plain",
+ "theme.signal": "Signal",
+ "title": "Fiesta:一个样式表里的设计系统",
+ "why.a11y.body": "对比度按 WCAG 校验,真正的焦点环,高对比度模式和打印都已处理。",
+ "why.a11y.title": "默认无障碍",
+ "why.attrs.body": "一看就懂。没有一堆乱糟糟的 class。",
+ "why.attrs.title": "朴素的 HTML 属性",
+ "why.dark.body": "跟随系统,或用你自己加的开关。每种颜色都在两种模式下校验过。",
+ "why.dark.title": "浅色与深色,内置",
+ "why.depth.body": "按钮会按下去,卡片会接住光,光会跟着你的指针走。",
+ "why.depth.title": "有生命感的层次",
+ "why.link.body": "粘贴一个样式表标签即可。任何页面、任何框架,或者不用框架,都能用。",
+ "why.link.title": "一个链接,无需构建",
+ "why.rtl.body": "阿拉伯语、希伯来语和其他任何文字都能正确排版,无需额外 CSS。",
+ "why.rtl.title": "支持从右到左"
+}