cms/resources/js/components/admin/TranslationManager.svelte

193 lines
7.2 KiB
Svelte
Raw Permalink Normal View History

<script>
let { adminPath, locale = 'en', overrides = [], availableLocales = ['en', 'es', 'fr', 'de'] } = $props();
let items = $state([]);
let newLocale = $state('en');
let newGroup = $state('cms');
let newKey = $state('');
let newValue = $state('');
$effect(() => {
items = overrides;
newLocale = locale;
});
let loading = $state(false);
let message = $state(null);
async function saveTranslation(item = null) {
loading = true;
message = null;
const data = item ? {
locale: item.locale,
group: item.group,
key: item.key,
value: item.value
} : {
locale: newLocale,
group: newGroup,
key: newKey,
value: newValue
};
try {
const response = await fetch(`${adminPath}/translations`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
},
body: JSON.stringify(data)
});
if (response.ok) {
if (!item) {
items = [...items, { ...data, id: Date.now() }];
newKey = '';
newValue = '';
}
message = { type: 'success', text: 'Translation saved successfully!' };
} else {
message = { type: 'error', text: 'Failed to save translation.' };
}
} catch (error) {
message = { type: 'error', text: 'An error occurred.' };
} finally {
loading = false;
}
}
function switchLocale(l) {
window.location.href = `${adminPath}/translations?locale=${l}`;
}
</script>
<div class="ui container">
<div class="ui grid">
<div class="row">
<div class="column">
<h1 class="ui header">
<i class="language icon"></i>
<div class="content">
Translation Manager
<div class="sub header">Override system and plugin strings in the database.</div>
</div>
</h1>
</div>
</div>
<div class="row">
<div class="column">
<div class="ui segment">
<div class="ui form">
<div class="inline fields">
<span>Current Locale:</span>
{#each availableLocales as l}
<div class="field">
<button
type="button"
class="ui {locale === l ? 'primary' : ''} button"
onclick={() => switchLocale(l)}
>
{(l || '').toUpperCase()}
</button>
</div>
{/each}
</div>
</div>
</div>
</div>
</div>
{#if message}
<div class="row">
<div class="column">
<div class="ui {message.type} message">
{message.text}
</div>
</div>
</div>
{/if}
<div class="row">
<div class="column">
<div class="ui segment">
<h3 class="ui header">Add New Override</h3>
<div class="ui form">
<div class="four fields">
<div class="field">
<label for="newGroup">Group</label>
<input type="text" id="newGroup" bind:value={newGroup} placeholder="e.g. cms, blog">
</div>
<div class="field">
<label for="newKey">Key</label>
<input type="text" id="newKey" bind:value={newKey} placeholder="e.g. navigation.home">
</div>
<div class="field">
<label for="newValue">Value</label>
<input type="text" id="newValue" bind:value={newValue} placeholder="Translated text">
</div>
<div class="field">
<label for="saveBtn">&nbsp;</label>
<button
type="button"
id="saveBtn"
class="ui fluid green button {loading ? 'loading' : ''}"
onclick={() => saveTranslation()}
disabled={!newKey || !newValue}
>
Add Override
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="column">
<table class="ui celled table">
<thead>
<tr>
<th>Group</th>
<th>Key</th>
<th>Value (Override)</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{#each items as item}
<tr>
<td class="collapsing">{item.group}</td>
<td class="collapsing"><code>{item.key}</code></td>
<td>
<div class="ui fluid input">
<input type="text" bind:value={item.value}>
</div>
</td>
<td class="collapsing">
<button
type="button"
class="ui blue icon button {loading ? 'loading' : ''}"
onclick={() => saveTranslation(item)}
title="Save"
>
<i class="save icon"></i>
</button>
</td>
</tr>
{/each}
{#if items.length === 0}
<tr>
<td colspan="4" class="center aligned">No overrides for this locale yet.</td>
</tr>
{/if}
</tbody>
</table>
</div>
</div>
</div>
</div>