Tovább a tartalomhoz

Többnyelvűség (i18n)

Az ElyOS adatbázis-alapú i18n rendszert használ. A fordítások az adatbázisban tárolódnak (nem statikus JSON fájlokban), és futásidőben töltődnek be. Ez lehetővé teszi a fordítások admin felületen keresztüli szerkesztését újraindítás nélkül.

Alapértelmezett nyelvek: hu (magyar) és en (angol).

A fordítások névterekbe vannak szervezve. Minden névtér egy funkcionális területnek felel meg:

platform:common # Közös szövegek (mentés, mégse, stb.)
platform:auth # Autentikáció
platform:settings # Beállítások alkalmazás
platform:users # Felhasználók alkalmazás
platform:chat # Chat alkalmazás
...

A legegyszerűbb módja a fordítások megjelenítésének a T komponens:

<script lang="ts">
import T from '$lib/components/i18n/T.svelte';
</script>
<!-- Egyszerű fordítás -->
<T key="platform:common.save" />
<!-- Paraméterekkel -->
<T key="platform:common.welcome" params={{ name: 'Felhasználó' }} />
<!-- Fallback szöveg -->
<T key="platform:common.unknown_key" fallback="Ismeretlen" />
import { getI18nService } from '$lib/i18n';
const i18n = getI18nService();
// Fordítás lekérése
const text = i18n.t('platform:common.save');
// Paraméterekkel
const welcome = i18n.t('platform:common.welcome', { name: 'Felhasználó' });
// Aktuális locale
const locale = i18n.locale; // 'hu' | 'en'
import { setLocale } from '$lib/i18n/preference.client';
// Locale váltás (cookie-ba menti, oldalt frissíti)
await setLocale('en');

A LocaleSwitcher komponens ezt automatikusan kezeli:

<script lang="ts">
import LocaleSwitcher from '$lib/components/i18n/LocaleSwitcher.svelte';
</script>
<LocaleSwitcher />

Szerver oldalon a locals.locale tartalmazza az aktuális nyelvet:

export const myAction = command(schema, async () => {
const { locals } = getRequestEvent();
const locale = locals.locale; // 'hu' | 'en'
// ...
});

Kliens oldalon az i18n store-ból:

<script lang="ts">
import { getI18nStore } from '$lib/i18n/store.svelte';
const i18nStore = getI18nStore();
const locale = $derived(i18nStore.locale);
</script>

Új fordítás hozzáadása a core rendszerbe

Szekció neve “Új fordítás hozzáadása a core rendszerbe”

Ha a core rendszerbe fejlesztesz új funkciót, az új fordításokat seed fájlokba kell elhelyezni, hogy adatbázis újrainicializálás esetén is megmaradjanak.

A fordítások funkcionális területek szerint vannak szervezva:

Seed fájlMire való
translations_common.sqlKözös szövegek (gombok, státuszok, hibaüzenetek)
translations_settings.sqlBeállítások alkalmazás fordításai
translations_user.sqlFelhasználók alkalmazás fordításai
translations_log.sqlNapló alkalmazás fordításai
translations_desktop.sqlDesktop környezet (Window, Taskbar, StartMenu)
translations_auth.sqlAuth oldalak (bejelentkezés, regisztráció)
translations_notifications.sqlÉrtesítési rendszer fordításai
translations_plugin_manager.sqlPlugin Manager fordításai

2. Add hozzá a fordításokat a seed fájlhoz

Szekció neve “2. Add hozzá a fordításokat a seed fájlhoz”

Nyisd meg a megfelelő fájlt a packages/database/src/seeds/sql/platform/ mappában:

-- translations_myapp.sql
-- =============================================================================
-- MYAPP NAMESPACE - Az én alkalmazásom fordításai
-- =============================================================================
-- -----------------------------------------------------------------------------
-- MAGYAR (hu) fordítások
-- -----------------------------------------------------------------------------
INSERT INTO platform.translations (locale, namespace, key, value) VALUES
('hu', 'myapp', 'title', 'Az én alkalmazásom'),
('hu', 'myapp', 'description', 'Ez az alkalmazás leírása'),
('hu', 'myapp', 'buttons.create', 'Új létrehozása'),
('hu', 'myapp', 'list.empty', 'Nincs megjeleníthető elem'),
('hu', 'myapp', 'form.name.label', 'Név'),
('hu', 'myapp', 'form.name.placeholder', 'Adja meg a nevet')
ON CONFLICT (locale, namespace, key) DO UPDATE SET value = EXCLUDED.value, updated_at = NOW();
-- -----------------------------------------------------------------------------
-- ANGOL (en) fordítások
-- -----------------------------------------------------------------------------
INSERT INTO platform.translations (locale, namespace, key, value) VALUES
('en', 'myapp', 'title', 'My Application'),
('en', 'myapp', 'description', 'This is the application description'),
('en', 'myapp', 'buttons.create', 'Create New'),
('en', 'myapp', 'list.empty', 'No items to display'),
('en', 'myapp', 'form.name.label', 'Name'),
('en', 'myapp', 'form.name.placeholder', 'Enter name')
ON CONFLICT (locale, namespace, key) DO UPDATE SET value = EXCLUDED.value, updated_at = NOW();

3. Regisztráld a seed-et (ha új fájl)

Szekció neve “3. Regisztráld a seed-et (ha új fájl)”

Ha új seed fájlt hoztál létre, regisztráld a packages/database/src/seeds/config.ts fájlban:

export const seedConfig: Record<string, SeedDefinition> = {
// ... meglévő seed-ek
translations_myapp: {
file: 'platform/translations_myapp.sql',
dependsOn: ['locales'],
description: 'My App translations'
}
};
Terminál
# Csak az új fordításokat frissíti (idempotens)
bun db:seed
# Vagy csak a saját seed-edet
bun db:seed --no-truncate --only=translations_myapp
<script lang="ts">
import T from '$lib/components/i18n/T.svelte';
</script>
<h1><T key="myapp.title" /></h1>
<p><T key="myapp.description" /></p>
<button>
<T key="myapp.buttons.create" />
</button>

Teljes példa: Új alkalmazás fordításai

Szekció neve “Teljes példa: Új alkalmazás fordításai”

1. Hozd létre a seed fájlt:

Terminál
touch packages/database/src/seeds/sql/platform/translations_todo.sql

2. Add hozzá a fordításokat:

-- translations_todo.sql
-- =============================================================================
-- TODO NAMESPACE - Todo alkalmazás fordításai
-- =============================================================================
-- -----------------------------------------------------------------------------
-- MAGYAR (hu) fordítások
-- -----------------------------------------------------------------------------
INSERT INTO platform.translations (locale, namespace, key, value) VALUES
('hu', 'todo', 'title', 'Teendők'),
('hu', 'todo', 'menu.all', 'Összes'),
('hu', 'todo', 'menu.active', 'Aktív'),
('hu', 'todo', 'menu.completed', 'Befejezett'),
('hu', 'todo', 'list.empty', 'Nincs teendő'),
('hu', 'todo', 'form.add.placeholder', 'Mit kell elvégezni?'),
('hu', 'todo', 'buttons.add', 'Hozzáadás'),
('hu', 'todo', 'buttons.delete', 'Törlés'),
('hu', 'todo', 'buttons.complete', 'Befejezés'),
('hu', 'todo', 'status.completed', 'Befejezve'),
('hu', 'todo', 'status.active', 'Aktív')
ON CONFLICT (locale, namespace, key) DO UPDATE SET value = EXCLUDED.value, updated_at = NOW();
-- -----------------------------------------------------------------------------
-- ANGOL (en) fordítások
-- -----------------------------------------------------------------------------
INSERT INTO platform.translations (locale, namespace, key, value) VALUES
('en', 'todo', 'title', 'To-Do'),
('en', 'todo', 'menu.all', 'All'),
('en', 'todo', 'menu.active', 'Active'),
('en', 'todo', 'menu.completed', 'Completed'),
('en', 'todo', 'list.empty', 'No tasks'),
('en', 'todo', 'form.add.placeholder', 'What needs to be done?'),
('en', 'todo', 'buttons.add', 'Add'),
('en', 'todo', 'buttons.delete', 'Delete'),
('en', 'todo', 'buttons.complete', 'Complete'),
('en', 'todo', 'status.completed', 'Completed'),
('en', 'todo', 'status.active', 'Active')
ON CONFLICT (locale, namespace, key) DO UPDATE SET value = EXCLUDED.value, updated_at = NOW();

3. Regisztráld a config.ts-ben:

packages/database/src/seeds/config.ts
export const seedConfig: Record<string, SeedDefinition> = {
// ... meglévő seed-ek
translations_todo: {
file: 'platform/translations_todo.sql',
dependsOn: ['locales'],
description: 'Todo app translations'
}
};

4. Futtasd a seed-et:

Terminál
bun db:seed

5. Használd az alkalmazásban:

src/apps/todo/index.svelte
<script lang="ts">
import T from '$lib/components/i18n/T.svelte';
</script>
<div class="todo-app">
<h1><T key="todo.title" /></h1>
<nav>
<button><T key="todo.menu.all" /></button>
<button><T key="todo.menu.active" /></button>
<button><T key="todo.menu.completed" /></button>
</nav>
<input placeholder={$t('todo.form.add.placeholder')} />
<button><T key="todo.buttons.add" /></button>
</div>

Fordítás hozzáadása futásidőben (admin felület)

Szekció neve “Fordítás hozzáadása futásidőben (admin felület)”

Ha nem core fejlesztésről van szó, hanem futásidőben szeretnél fordítást hozzáadni:

import { translationRepository } from '$lib/server/database/repositories';
await translationRepository.upsert({
locale: 'hu',
namespace: 'myapp',
key: 'title',
value: 'Az én alkalmazásom'
});
await translationRepository.upsert({
locale: 'en',
namespace: 'myapp',
key: 'title',
value: 'My Application'
});

A hooks.server.ts inicializálja az i18n service-t és beállítja az adatbázis loadert:

// hooks.server.ts (részlet)
setDatabaseLoader(async (locale: string, namespace: string) => {
return translationRepository.findByLocaleAndNamespace(locale, namespace);
});

A locale meghatározásának sorrendje:

  1. Cookie (locale cookie)
  2. Accept-Language HTTP fejléc
  3. Alapértelmezett locale (DEFAULT_LOCALE env változó, alapértelmezés: hu)
VáltozóAlapértelmezettLeírás
SUPPORTED_LOCALEShu,enVesszővel elválasztott támogatott nyelvek
DEFAULT_LOCALEhuAlapértelmezett nyelv
  • Névtér: platform:[app-neve] vagy platform:common
  • Kulcs: snake_case vagy camelCase, ponttal elválasztott hierarchia
  • Példák:
    • platform:common.save → “Mentés”
    • platform:common.cancel → “Mégse”
    • platform:settings.appearance.title → “Megjelenés”
    • platform:users.list.empty → “Nincs felhasználó”

A I18nProvider komponens inicializálja az i18n kontextust a layout-ban. Általában a root layout tartalmazza — nem kell manuálisan hozzáadni az alkalmazásokhoz.