Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor localisation #107

Merged
merged 3 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 14 additions & 14 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,31 @@
"@hey-api/openapi-ts": "0.53.5",
"@sveltejs/adapter-auto": "^3.2.5",
"@sveltejs/adapter-static": "^3.0.5",
"@sveltejs/kit": "^2.5.28",
"@sveltejs/kit": "^2.6.4",
"@sveltejs/vite-plugin-svelte": "4.0.0-next.7",
"@tailwindcss/typography": "^0.5.15",
"@testing-library/svelte": "^5.2.1",
"@testing-library/svelte": "^5.2.3",
"@types/eslint": "^9.6.1",
"@vitest/coverage-v8": "^2.1.1",
"@vitest/coverage-v8": "^2.1.2",
"autoprefixer": "^10.4.20",
"eslint": "^9.11.1",
"eslint": "^9.12.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.44.0",
"flowbite": "^2.5.1",
"flowbite-svelte": "^0.46.17",
"eslint-plugin-svelte": "^2.44.1",
"flowbite": "^2.5.2",
"flowbite-svelte": "^0.46.23",
"flowbite-svelte-icons": "2.0.0-next.16",
"globals": "^15.9.0",
"globals": "^15.11.0",
"jsdom": "^25.0.1",
"prettier": "^3.3.3",
"prettier-plugin-svelte": "^3.2.6",
"prettier-plugin-tailwindcss": "^0.6.6",
"prettier-plugin-svelte": "^3.2.7",
"prettier-plugin-tailwindcss": "^0.6.8",
"svelte": "5.0.0-next.263",
"svelte-check": "^3.8.6",
"tailwindcss": "^3.4.13",
"typescript": "^5.6.2",
"typescript-eslint": "^8.7.0",
"vite": "^5.4.7",
"vitest": "^2.1.1"
"typescript": "^5.6.3",
"typescript-eslint": "^8.8.1",
"vite": "^5.4.8",
"vitest": "^2.1.2"
},
"type": "module",
"dependencies": {
Expand Down
916 changes: 456 additions & 460 deletions frontend/pnpm-lock.yaml

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion frontend/src/lib/admin.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ function AdminUser() {
return user;
},
login: async function (loginData: Body_auth_cookie_login_auth_login_post) {
console.log(loginData);
const { data, error } = await authCookieLogin({ body: loginData });
if (error) {
return error?.detail as string;
Expand Down
15 changes: 15 additions & 0 deletions frontend/src/lib/client/services.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ import type {
DeleteLanguageData,
DeleteLanguageError,
DeleteLanguageResponse,
UpdateI18NData,
UpdateI18NError,
UpdateI18NResponse,
GetMilestoneGroupsAdminError,
GetMilestoneGroupsAdminResponse,
CreateMilestoneGroupAdminError,
Expand Down Expand Up @@ -219,6 +222,18 @@ export const deleteLanguage = <ThrowOnError extends boolean = false>(
});
};

/**
* Update I18N
*/
export const updateI18N = <ThrowOnError extends boolean = false>(
options: Options<UpdateI18NData, ThrowOnError>
) => {
return (options?.client ?? client).put<UpdateI18NResponse, UpdateI18NError, ThrowOnError>({
...options,
url: '/admin/i18n/{language_id}'
});
};

/**
* Get Milestone Groups Admin
*/
Expand Down
17 changes: 16 additions & 1 deletion frontend/src/lib/client/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ export type ValidationError = {
};

export type GetLanguagesResponse = {
[key: string]: string;
[key: string]: number;
};

export type GetLanguagesError = unknown;
Expand Down Expand Up @@ -251,6 +251,21 @@ export type DeleteLanguageResponse = unknown;

export type DeleteLanguageError = HTTPValidationError;

export type UpdateI18NData = {
body: {
[key: string]: {
[key: string]: string;
};
};
path: {
language_id: number;
};
};

export type UpdateI18NResponse = unknown;

export type UpdateI18NError = HTTPValidationError;

export type GetMilestoneGroupsAdminResponse = Array<MilestoneGroupAdmin>;

export type GetMilestoneGroupsAdminError = unknown;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
{@const title = $_(`admin.${textKey}`)}
<div class="mb-5">
<Label class="mb-2">{title}</Label>
{#each Object.entries($languages) as [lang_id, lang]}
{#each Object.entries($languages) as [lang, lang_id]}
<div class="mb-1">
<ButtonGroup class="w-full">
<InputAddon>{lang}</InputAddon>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
{@const title = $_(`admin.${textKey}`)}
<div class="mb-5">
<Label class="mb-2">{title}</Label>
{#each Object.entries($languages) as [lang_id, lang]}
{#each Object.entries($languages) as [lang, lang_id]}
<div class="mb-1">
<ButtonGroup class="w-full">
<InputAddon>{lang}</InputAddon>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
<Label class="mb-2">Preview</Label>
<div class="flex flex-row">
<ButtonGroup class="mb-2 mr-2">
{#each Object.entries($languages) as [lang_id, lang]}
{#each Object.entries($languages) as [lang, lang_id]}
<Button
checked={preview_lang_id === lang_id}
on:click={(e) => {
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/lib/components/Admin/Languages.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import ISO6391 from 'iso-639-1';
import { _ } from 'svelte-i18n';
import type { SelectOptionType } from 'flowbite-svelte';
import { updateLanguages } from '$lib/i18n';
import { getTranslations } from '$lib/i18n';
import { languages } from '$lib/stores/langStore';
import DeleteModal from '$lib/components/Admin/DeleteModal.svelte';
import AddButton from '$lib/components/Admin/AddButton.svelte';
Expand All @@ -37,7 +37,7 @@
console.log(error);
} else {
console.log(data);
await updateLanguages();
await getTranslations();
}
}

Expand All @@ -49,7 +49,7 @@
console.log(error);
} else {
console.log(data);
await updateLanguages();
await getTranslations();
}
}
</script>
Expand All @@ -63,7 +63,7 @@
<TableHeadCell>Actions</TableHeadCell>
</TableHead>
<TableBody>
{#each Object.entries($languages) as [id, lang]}
{#each Object.entries($languages) as [lang, lang_id]}
<TableBodyRow>
<TableBodyCell>
{lang}
Expand All @@ -74,7 +74,7 @@
<TableBodyCell>
<DeleteButton
onclick={() => {
currentLanguageId = id;
currentLanguageId = lang_id;
showDeleteModal = true;
}}
/>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/lib/components/Admin/Login.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
</div>
<Button type="submit" class="mb-6">Login</Button>
{#if errorCode !== ''}
<Alert>{$_(errorCode)}</Alert>
<Alert>{$_(`login.${errorCode}`)}</Alert>
{/if}
</form>
</div>
Expand Down
93 changes: 93 additions & 0 deletions frontend/src/lib/components/Admin/Translations.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<svelte:options runes={true} />

<script lang="ts">
import {
Accordion,
AccordionItem,
ButtonGroup,
Card,
Input,
InputAddon,
Label,
P,
Table,
TableBody,
TableBodyCell,
TableBodyRow,
TableHead,
TableHeadCell
} from 'flowbite-svelte';
import { onMount } from 'svelte';
import { _ } from 'svelte-i18n';
import { getI18nJson, getTranslations } from '$lib/i18n';
import { languages } from '$lib/stores/langStore';
import { updateI18N } from '$lib/client/services.gen';
import SaveButton from '$lib/components/Admin/SaveButton.svelte';
import de from '../../../locales/de.json';

type Translation = Record<string, Record<string, string>>;
let translations = $state({} as Record<string, Translation>);

async function refreshTranslations() {
for (const [lang, lang_id] of Object.entries($languages)) {
if (lang !== 'de') {
translations[lang] = await getI18nJson(lang_id);
}
}
}

async function saveChanges() {
for (const lang of Object.keys(translations)) {
const { data, error } = await updateI18N({
body: translations[lang],
path: {
language_id: $languages[lang]
}
});
if (error) {
console.log(error);
return;
} else {
console.log(data);
}
}
await getTranslations();
}

onMount(() => refreshTranslations());
</script>

<Card size="xl" class="m-5">
<h3 class="mb-3 text-xl font-medium text-gray-900 dark:text-white">{$_('admin.translations')}</h3>
<Accordion flush>
{#each Object.entries(de) as [section_key, section]}
<AccordionItem>
<span slot="header" class="flex gap-2 text-base">
{section_key}
</span>
{#each Object.entries(section) as [item_key, item]}
<div class="m-2 mb-4 rounded-md border p-2">
<Label class="mb-2">{item_key}</Label>
<div class="mb-1">
<ButtonGroup class="w-full">
<InputAddon>de</InputAddon>
<p class="w-full rounded-r-md border px-2">{item}</p>
</ButtonGroup>
</div>
{#each Object.keys(translations) as lang}
<div class="mb-1">
<ButtonGroup class="w-full">
<InputAddon>{lang}</InputAddon>
<Input bind:value={translations[lang][section_key][item_key]} />
</ButtonGroup>
</div>
{/each}
</div>
{/each}
<div class="my-2 content-center">
<SaveButton onclick={saveChanges} />
</div>
</AccordionItem>
{/each}
</Accordion>
</Card>
2 changes: 1 addition & 1 deletion frontend/src/lib/components/LocaleChooser.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
class="flex items-center"
on:click={() => {
locale.set(loc);
lang_id.set(`${Object.keys($languages).find((key) => $languages[key] === loc)}`);
lang_id.set($languages[loc]);
dropdownOpen = false;
}}
>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/lib/components/Milestone.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,9 @@
onClick={() => {
selectAnswer(answerIndex);
}}
tooltip={$_(`milestone.answer${answerIndex}.description`)}
tooltip={$_(`milestone.answer${answerIndex}-desc`)}
>
{$_(`milestone.answer${answerIndex}.text`)}
{$_(`milestone.answer${answerIndex}-text`)}
</MilestoneButton>
{/each}
<div class="flex flex-row justify-center">
Expand Down
41 changes: 33 additions & 8 deletions frontend/src/lib/i18n.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,43 @@
import { register, init } from 'svelte-i18n';
import { init, addMessages } from 'svelte-i18n';
import { languages } from '$lib/stores/langStore';
import { getLanguages } from '$lib/client';
import de from '../locales/de.json';

register('de', () => import('../locales/de.json'));
register('en', () => import('../locales/en.json'));
export async function getI18nJson(lang_id: number) {
try {
const res = await fetch(`${import.meta.env.VITE_MONDEY_API_URL}/static/i18n/${lang_id}.json`);
if (!res.ok) {
console.log(
`getI18nJson failed for lang_id ${lang_id} with status ${res.status}, returning de translations`
);
return de;
}
return await res.json();
} catch {
console.log(`getI18nJson failed for lang_id ${lang_id}, returning de translations`);
return de;
}
}

init({
fallbackLocale: 'de',
initialLocale: 'de'
});
async function getTranslation(lang: string, lang_id: number) {
const json = await getI18nJson(lang_id);
addMessages(lang, json);
}

export async function updateLanguages() {
export async function getTranslations() {
const { data, error } = await getLanguages();
if (!error && data) {
languages.set(data);
Object.entries(data).forEach(([lang, lang_id]) => {
if (lang_id !== 1) {
getTranslation(lang, lang_id);
}
});
}
}

addMessages('de', de);
init({
fallbackLocale: 'de',
initialLocale: 'de'
});
Loading