Improve i18n (#61)

- add support for RTL languages
- fix bug with non-existent locale in localStorage
- add globe icon to detect the language field
This commit is contained in:
Nikita Karamov 2024-01-20 16:44:36 +01:00 committed by GitHub
commit 8304cf0f10
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 32 additions and 24 deletions

View file

@ -15,7 +15,10 @@ const { instance, errors } = Astro.props;
data-translate="instance" data-translate="instance"
> >
Fediverse instance Fediverse instance
<div class="instance-input"> <div
class="instance-input"
dir="ltr"
>
<span id="https-label">https://</span> <span id="https-label">https://</span>
<input <input
type="text" type="text"
@ -90,7 +93,7 @@ const { instance, errors } = Astro.props;
} }
#saved-instances { #saved-instances {
margin-bottom: 1rem; margin-block-end: 1rem;
> div { > div {
display: inline-block; display: inline-block;

View file

@ -11,8 +11,8 @@ import { languages } from "@i18n/translations";
const initialLanguage = "en"; const initialLanguage = "en";
--- ---
<label data-translate="language"> <label>
Language: 🌍 <span data-translate="language">Language:</span>
<select <select
name="language" name="language"
id="language" id="language"
@ -24,7 +24,7 @@ const initialLanguage = "en";
selected={k === initialLanguage} selected={k === initialLanguage}
value={k} value={k}
> >
{v} {v.autonym}
</option> </option>
); );
}) })

View file

@ -9,9 +9,6 @@
import { strings, defaultLanguage, languages } from "./translations"; import { strings, defaultLanguage, languages } from "./translations";
export function useTranslations(language: string) { export function useTranslations(language: string) {
if (!(language in strings)) {
language = defaultLanguage;
}
return function t( return function t(
key: keyof (typeof strings)[typeof defaultLanguage], key: keyof (typeof strings)[typeof defaultLanguage],
): string { ): string {
@ -46,6 +43,9 @@ export function findBestLanguage(): string {
} }
export function applyTranslations(language: string) { export function applyTranslations(language: string) {
if (!(language in strings)) {
language = defaultLanguage;
}
const t = useTranslations(language); const t = useTranslations(language);
for (const node of document.querySelectorAll("[data-translate]")) { for (const node of document.querySelectorAll("[data-translate]")) {
@ -71,4 +71,8 @@ export function applyTranslations(language: string) {
} }
} }
} }
document.documentElement.lang = language;
document.documentElement.dir =
languages[language as keyof typeof languages].dir;
} }

View file

@ -14,12 +14,12 @@ import nl from "./translations/nl.json";
import ru from "./translations/ru.json"; import ru from "./translations/ru.json";
export const languages = { export const languages = {
en: "English", en: { autonym: "English", dir: "ltr" },
de: "Deutsch", de: { autonym: "Deutsch", dir: "ltr" },
es: "Español", es: { autonym: "Español", dir: "ltr" },
fr: "Français", fr: { autonym: "Français", dir: "ltr" },
nl: "Nederlands", nl: { autonym: "Nederlands", dir: "ltr" },
ru: "Русский", ru: { autonym: "Русский", dir: "ltr" },
}; };
export const strings: Record<keyof typeof languages, Record<string, string>> = { export const strings: Record<keyof typeof languages, Record<string, string>> = {

View file

@ -39,7 +39,8 @@ html {
body { body {
max-width: 60em; max-width: 60em;
margin: 0 auto; margin-block: 0;
margin-inline: auto;
display: flex; display: flex;
flex-flow: row wrap; flex-flow: row wrap;
@ -55,19 +56,16 @@ header {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
> div {
text-align: right;
}
} }
main { main {
margin-bottom: 2rem; margin-block-end: 2rem;
} }
main, main,
aside { aside {
padding: 0 1rem; padding-block: 0;
padding-inline: 1rem;
} }
hr { hr {
@ -110,6 +108,7 @@ textarea {
textarea { textarea {
resize: vertical; resize: vertical;
resize: block;
} }
input[type="text"], input[type="text"],
@ -130,7 +129,8 @@ input[type="submit"] {
color: var(--s2f-button-text-color); color: var(--s2f-button-text-color);
font-weight: bolder; font-weight: bolder;
height: 2.5rem; height: 2.5rem;
padding: 0.5rem 1.5rem; padding-block: 0.5rem;
padding-inline: 1.5rem;
border: 0; border: 0;
cursor: pointer; cursor: pointer;
appearance: button; appearance: button;
@ -175,9 +175,10 @@ input[type="submit"] {
p.error { p.error {
color: var(--s2f-error-color); color: var(--s2f-error-color);
margin: 0 0 1rem; margin-block: 0 1rem;
margin-inline: 0;
} }
.mt1r { .mt1r {
margin-top: 1rem !important; margin-block-start: 1rem !important;
} }