feat: Migrate hardcoded strings to i18n calls

This commit is contained in:
Ased Mammad 2024-03-03 00:08:51 +03:30
parent 7a77f3c2c0
commit 3c471ee2ca
46 changed files with 492 additions and 381 deletions

View file

@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { onMount } from 'svelte'; import { onMount, getContext } from 'svelte';
import { Confetti } from 'svelte-confetti'; import { Confetti } from 'svelte-confetti';
import { WEBUI_NAME, config } from '$lib/stores'; import { WEBUI_NAME, config } from '$lib/stores';
@ -9,6 +9,8 @@
import Modal from './common/Modal.svelte'; import Modal from './common/Modal.svelte';
const i18n = getContext('i18n');
export let show = false; export let show = false;
let changelog = null; let changelog = null;
@ -45,7 +47,7 @@
</button> </button>
</div> </div>
<div class="flex items-center mt-1"> <div class="flex items-center mt-1">
<div class="text-sm dark:text-gray-200">Release Notes</div> <div class="text-sm dark:text-gray-200">{$i18n.t('Release Notes')}</div>
<div class="flex self-center w-[1px] h-6 mx-2.5 bg-gray-200 dark:bg-gray-700" /> <div class="flex self-center w-[1px] h-6 mx-2.5 bg-gray-200 dark:bg-gray-700" />
<div class="text-sm dark:text-gray-200"> <div class="text-sm dark:text-gray-200">
v{WEBUI_VERSION} v{WEBUI_VERSION}
@ -108,7 +110,7 @@
}} }}
class=" px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-gray-100 transition rounded" class=" px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-gray-100 transition rounded"
> >
<span class="relative">Okay, Let's Go!</span> <span class="relative">{$i18n.t("Okay, Let's Go!")}</span>
</button> </button>
</div> </div>
</div> </div>

View file

@ -2,11 +2,12 @@
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
import { onMount } from 'svelte'; import { onMount, getContext } from 'svelte';
import { updateUserById } from '$lib/apis/users'; import { updateUserById } from '$lib/apis/users';
import Modal from '../common/Modal.svelte'; import Modal from '../common/Modal.svelte';
const i18n = getContext('i18n');
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
export let show = false; export let show = false;
@ -42,7 +43,7 @@
<Modal size="sm" bind:show> <Modal size="sm" bind:show>
<div> <div>
<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> <div class=" flex justify-between dark:text-gray-300 px-5 py-4">
<div class=" text-lg font-medium self-center">Edit User</div> <div class=" text-lg font-medium self-center">{$i18n.t('Edit User')}</div>
<button <button
class="self-center" class="self-center"
on:click={() => { on:click={() => {
@ -93,7 +94,7 @@
<div class=" flex flex-col space-y-1.5"> <div class=" flex flex-col space-y-1.5">
<div class="flex flex-col w-full"> <div class="flex flex-col w-full">
<div class=" mb-1 text-xs text-gray-500">Email</div> <div class=" mb-1 text-xs text-gray-500">{$i18n.t('Email')}</div>
<div class="flex-1"> <div class="flex-1">
<input <input
@ -108,7 +109,7 @@
</div> </div>
<div class="flex flex-col w-full"> <div class="flex flex-col w-full">
<div class=" mb-1 text-xs text-gray-500">Name</div> <div class=" mb-1 text-xs text-gray-500">{$i18n.t('Name')}</div>
<div class="flex-1"> <div class="flex-1">
<input <input
@ -122,7 +123,7 @@
</div> </div>
<div class="flex flex-col w-full"> <div class="flex flex-col w-full">
<div class=" mb-1 text-xs text-gray-500">New Password</div> <div class=" mb-1 text-xs text-gray-500">{$i18n.t('New Password')}</div>
<div class="flex-1"> <div class="flex-1">
<input <input

View file

@ -1,6 +1,8 @@
<script lang="ts"> <script lang="ts">
import { downloadDatabase } from '$lib/apis/utils'; import { downloadDatabase } from '$lib/apis/utils';
import { onMount } from 'svelte'; import { onMount, getContext } from 'svelte';
const i18n = getContext('i18n');
export let saveHandler: Function; export let saveHandler: Function;
@ -17,10 +19,10 @@
> >
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80"> <div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80">
<div> <div>
<div class=" mb-2 text-sm font-medium">Database</div> <div class=" mb-2 text-sm font-medium">{$i18n.t('Database')}</div>
<div class=" flex w-full justify-between"> <div class=" flex w-full justify-between">
<!-- <div class=" self-center text-xs font-medium">Allow Chat Deletion</div> --> <!-- <div class=" self-center text-xs font-medium">{$i18n.t('Allow Chat Deletion')}</div> -->
<button <button
class=" flex rounded-md py-1.5 px-3 w-full hover:bg-gray-200 dark:hover:bg-gray-800 transition" class=" flex rounded-md py-1.5 px-3 w-full hover:bg-gray-200 dark:hover:bg-gray-800 transition"
@ -46,7 +48,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center text-sm font-medium">Download Database</div> <div class=" self-center text-sm font-medium">{$i18n.t('Download Database')}</div>
</button> </button>
</div> </div>
</div> </div>

View file

@ -7,7 +7,9 @@
updateDefaultUserRole, updateDefaultUserRole,
updateJWTExpiresDuration updateJWTExpiresDuration
} from '$lib/apis/auths'; } from '$lib/apis/auths';
import { onMount } from 'svelte'; import { onMount, getContext } from 'svelte';
const i18n = getContext('i18n');
export let saveHandler: Function; export let saveHandler: Function;
let signUpEnabled = true; let signUpEnabled = true;
@ -43,10 +45,10 @@
> >
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80"> <div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80">
<div> <div>
<div class=" mb-2 text-sm font-medium">General Settings</div> <div class=" mb-2 text-sm font-medium">{$i18n.t('General Settings')}</div>
<div class=" flex w-full justify-between"> <div class=" flex w-full justify-between">
<div class=" self-center text-xs font-medium">Enable New Sign Ups</div> <div class=" self-center text-xs font-medium">{$i18n.t('Enable New Sign Ups')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -66,7 +68,7 @@
d="M11.5 1A3.5 3.5 0 0 0 8 4.5V7H2.5A1.5 1.5 0 0 0 1 8.5v5A1.5 1.5 0 0 0 2.5 15h7a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 9.5 7V4.5a2 2 0 1 1 4 0v1.75a.75.75 0 0 0 1.5 0V4.5A3.5 3.5 0 0 0 11.5 1Z" d="M11.5 1A3.5 3.5 0 0 0 8 4.5V7H2.5A1.5 1.5 0 0 0 1 8.5v5A1.5 1.5 0 0 0 2.5 15h7a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 9.5 7V4.5a2 2 0 1 1 4 0v1.75a.75.75 0 0 0 1.5 0V4.5A3.5 3.5 0 0 0 11.5 1Z"
/> />
</svg> </svg>
<span class="ml-2 self-center">Enabled</span> <span class="ml-2 self-center">{$i18n.t('Enabled')}</span>
{:else} {:else}
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@ -81,13 +83,13 @@
/> />
</svg> </svg>
<span class="ml-2 self-center">Disabled</span> <span class="ml-2 self-center">{$i18n.t('Disabled')}</span>
{/if} {/if}
</button> </button>
</div> </div>
<div class=" flex w-full justify-between"> <div class=" flex w-full justify-between">
<div class=" self-center text-xs font-medium">Default User Role</div> <div class=" self-center text-xs font-medium">{$i18n.t('Default User Role')}</div>
<div class="flex items-center relative"> <div class="flex items-center relative">
<select <select
class="w-fit pr-8 rounded py-2 px-2 text-xs bg-transparent outline-none text-right" class="w-fit pr-8 rounded py-2 px-2 text-xs bg-transparent outline-none text-right"
@ -97,9 +99,9 @@
updateDefaultUserRoleHandler(e.target.value); updateDefaultUserRoleHandler(e.target.value);
}} }}
> >
<option value="pending">Pending</option> <option value="pending">{$i18n.t('Pending')}</option>
<option value="user">User</option> <option value="user">{$i18n.t('User')}</option>
<option value="admin">Admin</option> <option value="admin">{$i18n.t('Admin')}</option>
</select> </select>
</div> </div>
</div> </div>
@ -108,7 +110,7 @@
<div class=" w-full justify-between"> <div class=" w-full justify-between">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">JWT Expiration</div> <div class=" self-center text-xs font-medium">{$i18n.t('JWT Expiration')}</div>
</div> </div>
<div class="flex mt-2 space-x-2"> <div class="flex mt-2 space-x-2">

View file

@ -1,7 +1,9 @@
<script lang="ts"> <script lang="ts">
import { getSignUpEnabledStatus, toggleSignUpEnabledStatus } from '$lib/apis/auths'; import { getSignUpEnabledStatus, toggleSignUpEnabledStatus } from '$lib/apis/auths';
import { getUserPermissions, updateUserPermissions } from '$lib/apis/users'; import { getUserPermissions, updateUserPermissions } from '$lib/apis/users';
import { onMount } from 'svelte'; import { onMount, getContext } from 'svelte';
const i18n = getContext('i18n');
export let saveHandler: Function; export let saveHandler: Function;
@ -26,10 +28,10 @@
> >
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80"> <div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80">
<div> <div>
<div class=" mb-2 text-sm font-medium">User Permissions</div> <div class=" mb-2 text-sm font-medium">{$i18n.t('User Permissions')}</div>
<div class=" flex w-full justify-between"> <div class=" flex w-full justify-between">
<div class=" self-center text-xs font-medium">Allow Chat Deletion</div> <div class=" self-center text-xs font-medium">{$i18n.t('Allow Chat Deletion')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -49,7 +51,7 @@
d="M11.5 1A3.5 3.5 0 0 0 8 4.5V7H2.5A1.5 1.5 0 0 0 1 8.5v5A1.5 1.5 0 0 0 2.5 15h7a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 9.5 7V4.5a2 2 0 1 1 4 0v1.75a.75.75 0 0 0 1.5 0V4.5A3.5 3.5 0 0 0 11.5 1Z" d="M11.5 1A3.5 3.5 0 0 0 8 4.5V7H2.5A1.5 1.5 0 0 0 1 8.5v5A1.5 1.5 0 0 0 2.5 15h7a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 9.5 7V4.5a2 2 0 1 1 4 0v1.75a.75.75 0 0 0 1.5 0V4.5A3.5 3.5 0 0 0 11.5 1Z"
/> />
</svg> </svg>
<span class="ml-2 self-center">Allow</span> <span class="ml-2 self-center">{$i18n.t('Allow')}</span>
{:else} {:else}
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@ -64,7 +66,7 @@
/> />
</svg> </svg>
<span class="ml-2 self-center">Don't Allow</span> <span class="ml-2 self-center">{$i18n.t("Don't Allow")}</span>
{/if} {/if}
</button> </button>
</div> </div>

View file

@ -1,10 +1,13 @@
<script> <script>
import { getContext } from 'svelte';
import Modal from '../common/Modal.svelte'; import Modal from '../common/Modal.svelte';
import Database from './Settings/Database.svelte'; import Database from './Settings/Database.svelte';
import General from './Settings/General.svelte'; import General from './Settings/General.svelte';
import Users from './Settings/Users.svelte'; import Users from './Settings/Users.svelte';
const i18n = getContext('i18n');
export let show = false; export let show = false;
let selectedTab = 'general'; let selectedTab = 'general';
@ -13,7 +16,7 @@
<Modal bind:show> <Modal bind:show>
<div> <div>
<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> <div class=" flex justify-between dark:text-gray-300 px-5 py-4">
<div class=" text-lg font-medium self-center">Admin Settings</div> <div class=" text-lg font-medium self-center">{$i18n.t('Admin Settings')}</div>
<button <button
class="self-center" class="self-center"
on:click={() => { on:click={() => {
@ -61,7 +64,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center">General</div> <div class=" self-center">{$i18n.t('General')}</div>
</button> </button>
<button <button
@ -85,7 +88,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center">Users</div> <div class=" self-center">{$i18n.t('Users')}</div>
</button> </button>
<button <button
@ -113,7 +116,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center">Database</div> <div class=" self-center">{$i18n.t('Database')}</div>
</button> </button>
</div> </div>
<div class="flex-1 md:min-h-[380px]"> <div class="flex-1 md:min-h-[380px]">

View file

@ -220,7 +220,7 @@
isRecording = false; isRecording = false;
}; };
} else { } else {
toast.error('SpeechRecognition API is not supported in this browser.'); toast.error($i18n.t('SpeechRecognition API is not supported in this browser.'));
} }
} }
} }
@ -341,12 +341,15 @@
uploadDoc(file); uploadDoc(file);
} else { } else {
toast.error( toast.error(
`Unknown File Type '${file['type']}', but accepting and treating as plain text` $i18n.t(
`Unknown File Type '{{file_type}}', but accepting and treating as plain text`,
{ file_type: file['type'] }
)
); );
uploadDoc(file); uploadDoc(file);
} }
} else { } else {
toast.error(`File not found.`); toast.error($i18n.t(`File not found.`));
} }
} }
@ -485,13 +488,16 @@
filesInputElement.value = ''; filesInputElement.value = '';
} else { } else {
toast.error( toast.error(
`Unknown File Type '${file['type']}', but accepting and treating as plain text` $i18n.t(
`Unknown File Type '{{file_type}}', but accepting and treating as plain text`,
{ file_type: file['type'] }
)
); );
uploadDoc(file); uploadDoc(file);
filesInputElement.value = ''; filesInputElement.value = '';
} }
} else { } else {
toast.error(`File not found.`); toast.error($i18n.t(`File not found.`));
} }
}} }}
/> />
@ -578,7 +584,7 @@
{file.name} {file.name}
</div> </div>
<div class=" text-gray-500 text-sm">Document</div> <div class=" text-gray-500 text-sm">{$i18n.t('Document')}</div>
</div> </div>
</div> </div>
{:else if file.type === 'collection'} {:else if file.type === 'collection'}
@ -606,7 +612,7 @@
{file?.title ?? `#${file.name}`} {file?.title ?? `#${file.name}`}
</div> </div>
<div class=" text-gray-500 text-sm">Collection</div> <div class=" text-gray-500 text-sm">{$i18n.t('Collection')}</div>
</div> </div>
</div> </div>
{/if} {/if}
@ -640,7 +646,7 @@
<div class=" flex"> <div class=" flex">
{#if fileUploadEnabled} {#if fileUploadEnabled}
<div class=" self-end mb-2 ml-1"> <div class=" self-end mb-2 ml-1">
<Tooltip content="Upload files"> <Tooltip content={$i18n.t('Upload files')}>
<button <button
class="bg-gray-50 hover:bg-gray-100 text-gray-800 dark:bg-gray-850 dark:text-white dark:hover:bg-gray-800 transition rounded-full p-1.5" class="bg-gray-50 hover:bg-gray-100 text-gray-800 dark:bg-gray-850 dark:text-white dark:hover:bg-gray-800 transition rounded-full p-1.5"
type="button" type="button"
@ -811,7 +817,7 @@
<div class="self-end mb-2 flex space-x-1 mr-1"> <div class="self-end mb-2 flex space-x-1 mr-1">
{#if messages.length == 0 || messages.at(-1).done == true} {#if messages.length == 0 || messages.at(-1).done == true}
<Tooltip content="Record voice"> <Tooltip content={$i18n.t('Record voice')}>
{#if speechRecognitionEnabled} {#if speechRecognitionEnabled}
<button <button
id="voice-input-button" id="voice-input-button"
@ -880,7 +886,7 @@
{/if} {/if}
</Tooltip> </Tooltip>
<Tooltip content="Send message"> <Tooltip content={$i18n.t('Send message')}>
<button <button
class="{prompt !== '' class="{prompt !== ''
? 'bg-black text-white hover:bg-gray-900 dark:bg-white dark:text-black dark:hover:bg-gray-100 ' ? 'bg-black text-white hover:bg-gray-900 dark:bg-white dark:text-black dark:hover:bg-gray-100 '
@ -926,7 +932,7 @@
</form> </form>
<div class="mt-1.5 text-xs text-gray-500 text-center"> <div class="mt-1.5 text-xs text-gray-500 text-center">
LLMs can make mistakes. Verify important information. {$i18n.t('LLMs can make mistakes. Verify important information.')}
</div> </div>
</div> </div>
</div> </div>

View file

@ -3,9 +3,11 @@
import { documents } from '$lib/stores'; import { documents } from '$lib/stores';
import { removeFirstHashWord, isValidHttpUrl } from '$lib/utils'; import { removeFirstHashWord, isValidHttpUrl } from '$lib/utils';
import { tick } from 'svelte'; import { tick, getContext } from 'svelte';
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
const i18n = getContext('i18n');
export let prompt = ''; export let prompt = '';
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
@ -117,7 +119,7 @@
{doc?.title ?? `#${doc.name}`} {doc?.title ?? `#${doc.name}`}
</div> </div>
<div class=" text-xs text-gray-600 line-clamp-1">Collection</div> <div class=" text-xs text-gray-600 line-clamp-1">{$i18n.t('Collection')}</div>
{:else} {:else}
<div class=" font-medium text-black line-clamp-1"> <div class=" font-medium text-black line-clamp-1">
#{doc.name} ({doc.filename}) #{doc.name} ({doc.filename})
@ -140,7 +142,9 @@
confirmSelectWeb(url); confirmSelectWeb(url);
} else { } else {
toast.error( toast.error(
'Oops! Looks like the URL is invalid. Please double-check and try again.' $i18n.t(
'Oops! Looks like the URL is invalid. Please double-check and try again.'
)
); );
} }
}} }}
@ -149,7 +153,7 @@
{prompt.split(' ')?.at(0)?.substring(1)} {prompt.split(' ')?.at(0)?.substring(1)}
</div> </div>
<div class=" text-xs text-gray-600 line-clamp-1">Web</div> <div class=" text-xs text-gray-600 line-clamp-1">{$i18n.t('Web')}</div>
</button> </button>
{/if} {/if}
</div> </div>

View file

@ -43,7 +43,7 @@
user = JSON.parse(JSON.stringify(model.name)); user = JSON.parse(JSON.stringify(model.name));
await tick(); await tick();
chatInputPlaceholder = `'${model.name}' is thinking...`; chatInputPlaceholder = $i18n.t('{{modelName}} is thinking...', { modelName: model.name });
const chatInputElement = document.getElementById('chat-textarea'); const chatInputElement = document.getElementById('chat-textarea');
@ -111,7 +111,7 @@
toast.error(error.error); toast.error(error.error);
} }
} else { } else {
toast.error(`Uh-oh! There was an issue connecting to Ollama.`); toast.error($i18n.t('Uh-oh! There was an issue connecting to llama.'));
} }
} }

View file

@ -1,9 +1,11 @@
<script lang="ts"> <script lang="ts">
import { prompts } from '$lib/stores'; import { prompts } from '$lib/stores';
import { findWordIndices } from '$lib/utils'; import { findWordIndices } from '$lib/utils';
import { tick } from 'svelte'; import { tick, getContext } from 'svelte';
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
const i18n = getContext('i18n');
export let prompt = ''; export let prompt = '';
let selectedCommandIdx = 0; let selectedCommandIdx = 0;
let filteredPromptCommands = []; let filteredPromptCommands = [];
@ -29,7 +31,7 @@
if (command.content.includes('{{CLIPBOARD}}')) { if (command.content.includes('{{CLIPBOARD}}')) {
const clipboardText = await navigator.clipboard.readText().catch((err) => { const clipboardText = await navigator.clipboard.readText().catch((err) => {
toast.error('Failed to read clipboard contents'); toast.error($i18n.t('Failed to read clipboard contents'));
return '{{CLIPBOARD}}'; return '{{CLIPBOARD}}';
}); });
@ -113,8 +115,9 @@
</div> </div>
<div class="line-clamp-1"> <div class="line-clamp-1">
Tip: Update multiple variable slots consecutively by pressing the tab key in the chat {$i18n.t(
input after each replacement. 'Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.'
)}
</div> </div>
</div> </div>
</div> </div>

View file

@ -2,7 +2,7 @@
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { chats, config, modelfiles, settings, user } from '$lib/stores'; import { chats, config, modelfiles, settings, user } from '$lib/stores';
import { tick } from 'svelte'; import { tick, getContext } from 'svelte';
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
import { getChatList, updateChatById } from '$lib/apis/chats'; import { getChatList, updateChatById } from '$lib/apis/chats';
@ -13,6 +13,8 @@
import Spinner from '../common/Spinner.svelte'; import Spinner from '../common/Spinner.svelte';
import { imageGenerations } from '$lib/apis/images'; import { imageGenerations } from '$lib/apis/images';
const i18n = getContext('i18n');
export let chatId = ''; export let chatId = '';
export let sendPrompt: Function; export let sendPrompt: Function;
export let continueGeneration: Function; export let continueGeneration: Function;
@ -67,7 +69,7 @@
navigator.clipboard.writeText(text).then( navigator.clipboard.writeText(text).then(
function () { function () {
console.log('Async: Copying to clipboard was successful!'); console.log('Async: Copying to clipboard was successful!');
toast.success('Copying to clipboard was successful!'); toast.success($i18n.t('Copying to clipboard was successful!'));
}, },
function (err) { function (err) {
console.error('Async: Could not copy text: ', err); console.error('Async: Could not copy text: ', err);

View file

@ -7,7 +7,9 @@
import 'katex/dist/katex.min.css'; import 'katex/dist/katex.min.css';
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
import { onMount, tick } from 'svelte'; import { onMount, tick, getContext } from 'svelte';
const i18n = getContext('i18n');
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
@ -355,7 +357,7 @@
editMessageConfirmHandler(); editMessageConfirmHandler();
}} }}
> >
Save {$i18n.t('Save')}
</button> </button>
<button <button
@ -364,7 +366,7 @@
cancelEditMessage(); cancelEditMessage();
}} }}
> >
Cancel {$i18n.t('Cancel')}
</button> </button>
</div> </div>
</div> </div>

View file

@ -1,11 +1,13 @@
<script lang="ts"> <script lang="ts">
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { tick, createEventDispatcher } from 'svelte'; import { tick, createEventDispatcher, getContext } from 'svelte';
import Name from './Name.svelte'; import Name from './Name.svelte';
import ProfileImage from './ProfileImage.svelte'; import ProfileImage from './ProfileImage.svelte';
import { modelfiles, settings } from '$lib/stores'; import { modelfiles, settings } from '$lib/stores';
const i18n = getContext('i18n');
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
export let user; export let user;
@ -123,7 +125,7 @@
{file.name} {file.name}
</div> </div>
<div class=" text-gray-500 text-sm">Document</div> <div class=" text-gray-500 text-sm">{$i18n.t('Document')}</div>
</div> </div>
</button> </button>
{:else if file.type === 'collection'} {:else if file.type === 'collection'}
@ -152,7 +154,7 @@
{file?.title ?? `#${file.name}`} {file?.title ?? `#${file.name}`}
</div> </div>
<div class=" text-gray-500 text-sm">Collection</div> <div class=" text-gray-500 text-sm">{$i18n.t('Collection')}</div>
</div> </div>
</button> </button>
{/if} {/if}
@ -179,7 +181,7 @@
editMessageConfirmHandler(); editMessageConfirmHandler();
}} }}
> >
Save & Submit {$i18n.t('Save & Submit')}
</button> </button>
<button <button
@ -188,7 +190,7 @@
cancelEditMessage(); cancelEditMessage();
}} }}
> >
Cancel {$i18n.t('Cancel')}
</button> </button>
</div> </div>
</div> </div>

View file

@ -12,7 +12,7 @@
const saveDefaultModel = async () => { const saveDefaultModel = async () => {
const hasEmptyModel = selectedModels.filter((it) => it === ''); const hasEmptyModel = selectedModels.filter((it) => it === '');
if (hasEmptyModel.length) { if (hasEmptyModel.length) {
toast.error('Choose a model before saving...'); toast.error($i18n.t('Choose a model before saving...'));
return; return;
} }
settings.set({ ...$settings, models: selectedModels }); settings.set({ ...$settings, models: selectedModels });
@ -22,7 +22,7 @@
console.log('setting default models globally'); console.log('setting default models globally');
await setDefaultModels(localStorage.token, selectedModels.join(',')); await setDefaultModels(localStorage.token, selectedModels.join(','));
} }
toast.success('Default model updated'); toast.success($i18n.t('Default model updated'));
}; };
$: if (selectedModels.length > 0 && $models.length > 0) { $: if (selectedModels.length > 0 && $models.length > 0) {

View file

@ -4,7 +4,9 @@
import { WEBUI_VERSION } from '$lib/constants'; import { WEBUI_VERSION } from '$lib/constants';
import { WEBUI_NAME, config, showChangelog } from '$lib/stores'; import { WEBUI_NAME, config, showChangelog } from '$lib/stores';
import { compareVersion } from '$lib/utils'; import { compareVersion } from '$lib/utils';
import { onMount } from 'svelte'; import { onMount, getContext } from 'svelte';
const i18n = getContext('i18n');
let ollamaVersion = ''; let ollamaVersion = '';
@ -88,7 +90,7 @@
<hr class=" dark:border-gray-700" /> <hr class=" dark:border-gray-700" />
<div> <div>
<div class=" mb-2.5 text-sm font-medium">Ollama Version</div> <div class=" mb-2.5 text-sm font-medium">{$i18n.t('Ollama Version')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1 text-xs text-gray-700 dark:text-gray-200"> <div class="flex-1 text-xs text-gray-700 dark:text-gray-200">
{ollamaVersion ?? 'N/A'} {ollamaVersion ?? 'N/A'}

View file

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
import { onMount } from 'svelte'; import { onMount, getContext } from 'svelte';
import { user } from '$lib/stores'; import { user } from '$lib/stores';
import { updateUserProfile } from '$lib/apis/auths'; import { updateUserProfile } from '$lib/apis/auths';
@ -9,6 +9,8 @@
import { getGravatarUrl } from '$lib/apis/utils'; import { getGravatarUrl } from '$lib/apis/utils';
import { copyToClipboard } from '$lib/utils'; import { copyToClipboard } from '$lib/utils';
const i18n = getContext('i18n');
export let saveHandler: Function; export let saveHandler: Function;
let profileImageUrl = ''; let profileImageUrl = '';
@ -99,7 +101,7 @@
}} }}
/> />
<div class=" mb-2.5 text-sm font-medium">Profile</div> <div class=" mb-2.5 text-sm font-medium">{$i18n.t('Profile')}</div>
<div class="flex space-x-5"> <div class="flex space-x-5">
<div class="flex flex-col"> <div class="flex flex-col">
@ -147,7 +149,7 @@
<div class="flex-1"> <div class="flex-1">
<div class="flex flex-col w-full"> <div class="flex flex-col w-full">
<div class=" mb-1 text-xs text-gray-500">Name</div> <div class=" mb-1 text-xs text-gray-500">{$i18n.t('Name')}</div>
<div class="flex-1"> <div class="flex-1">
<input <input
@ -168,7 +170,7 @@
<div class=" w-full justify-between"> <div class=" w-full justify-between">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">JWT Token</div> <div class=" self-center text-xs font-medium">{$i18n.t('JWT Token')}</div>
</div> </div>
<div class="flex mt-2"> <div class="flex mt-2">

View file

@ -1,7 +1,10 @@
<script lang="ts"> <script lang="ts">
import { getContext } from 'svelte';
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
import { updateUserPassword } from '$lib/apis/auths'; import { updateUserPassword } from '$lib/apis/auths';
const i18n = getContext('i18n');
let show = false; let show = false;
let currentPassword = ''; let currentPassword = '';
let newPassword = ''; let newPassword = '';
@ -17,7 +20,7 @@
); );
if (res) { if (res) {
toast.success('Successfully updated.'); toast.success($i18n.t('Successfully updated.'));
} }
currentPassword = ''; currentPassword = '';
@ -40,7 +43,7 @@
}} }}
> >
<div class="flex justify-between items-center text-sm"> <div class="flex justify-between items-center text-sm">
<div class=" font-medium">Change Password</div> <div class=" font-medium">{$i18n.t('Change Password')}</div>
<button <button
class=" text-xs font-medium text-gray-500" class=" text-xs font-medium text-gray-500"
type="button" type="button"
@ -53,7 +56,7 @@
{#if show} {#if show}
<div class=" py-2.5 space-y-1.5"> <div class=" py-2.5 space-y-1.5">
<div class="flex flex-col w-full"> <div class="flex flex-col w-full">
<div class=" mb-1 text-xs text-gray-500">Current Password</div> <div class=" mb-1 text-xs text-gray-500">{$i18n.t('Current Password')}</div>
<div class="flex-1"> <div class="flex-1">
<input <input
@ -67,7 +70,7 @@
</div> </div>
<div class="flex flex-col w-full"> <div class="flex flex-col w-full">
<div class=" mb-1 text-xs text-gray-500">New Password</div> <div class=" mb-1 text-xs text-gray-500">{$i18n.t('New Password')}</div>
<div class="flex-1"> <div class="flex-1">
<input <input
@ -81,7 +84,7 @@
</div> </div>
<div class="flex flex-col w-full"> <div class="flex flex-col w-full">
<div class=" mb-1 text-xs text-gray-500">Confirm Password</div> <div class=" mb-1 text-xs text-gray-500">{$i18n.t('Confirm Password')}</div>
<div class="flex-1"> <div class="flex-1">
<input <input

View file

@ -1,8 +1,10 @@
<script lang="ts"> <script lang="ts">
import { createEventDispatcher, onMount } from 'svelte'; import { createEventDispatcher, onMount, getContext } from 'svelte';
import AdvancedParams from './Advanced/AdvancedParams.svelte';
const i18n = getContext('i18n');
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
import AdvancedParams from './Advanced/AdvancedParams.svelte';
export let saveSettings: Function; export let saveSettings: Function;
// Advanced // Advanced
@ -55,14 +57,14 @@
<div class="flex flex-col h-full justify-between text-sm"> <div class="flex flex-col h-full justify-between text-sm">
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80"> <div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80">
<div class=" text-sm font-medium">Parameters</div> <div class=" text-sm font-medium">{$i18n.t('Parameters')}</div>
<AdvancedParams bind:options /> <AdvancedParams bind:options />
<hr class=" dark:border-gray-700" /> <hr class=" dark:border-gray-700" />
<div class=" py-1 w-full justify-between"> <div class=" py-1 w-full justify-between">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">Keep Alive</div> <div class=" self-center text-xs font-medium">{$i18n.t('Keep Alive')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -72,9 +74,9 @@
}} }}
> >
{#if keepAlive === null} {#if keepAlive === null}
<span class="ml-2 self-center"> Default </span> <span class="ml-2 self-center">{$i18n.t(' Default ')}</span>
{:else} {:else}
<span class="ml-2 self-center"> Custom </span> <span class="ml-2 self-center">{$i18n.t(' Custom ')}</span>
{/if} {/if}
</button> </button>
</div> </div>
@ -93,7 +95,7 @@
<div> <div>
<div class=" py-1 flex w-full justify-between"> <div class=" py-1 flex w-full justify-between">
<div class=" self-center text-sm font-medium">Request Mode</div> <div class=" self-center text-sm font-medium">{$i18n.t('Request Mode')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -102,7 +104,7 @@
}} }}
> >
{#if requestFormat === ''} {#if requestFormat === ''}
<span class="ml-2 self-center"> Default </span> <span class="ml-2 self-center">{$i18n.t(' Default ')}</span>
{:else if requestFormat === 'json'} {:else if requestFormat === 'json'}
<!-- <svg <!-- <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@ -114,7 +116,7 @@
d="M10 2a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5A.75.75 0 0110 2zM10 15a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5A.75.75 0 0110 15zM10 7a3 3 0 100 6 3 3 0 000-6zM15.657 5.404a.75.75 0 10-1.06-1.06l-1.061 1.06a.75.75 0 001.06 1.06l1.06-1.06zM6.464 14.596a.75.75 0 10-1.06-1.06l-1.06 1.06a.75.75 0 001.06 1.06l1.06-1.06zM18 10a.75.75 0 01-.75.75h-1.5a.75.75 0 010-1.5h1.5A.75.75 0 0118 10zM5 10a.75.75 0 01-.75.75h-1.5a.75.75 0 010-1.5h1.5A.75.75 0 015 10zM14.596 15.657a.75.75 0 001.06-1.06l-1.06-1.061a.75.75 0 10-1.06 1.06l1.06 1.06zM5.404 6.464a.75.75 0 001.06-1.06l-1.06-1.06a.75.75 0 10-1.061 1.06l1.06 1.06z" d="M10 2a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5A.75.75 0 0110 2zM10 15a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5A.75.75 0 0110 15zM10 7a3 3 0 100 6 3 3 0 000-6zM15.657 5.404a.75.75 0 10-1.06-1.06l-1.061 1.06a.75.75 0 001.06 1.06l1.06-1.06zM6.464 14.596a.75.75 0 10-1.06-1.06l-1.06 1.06a.75.75 0 001.06 1.06l1.06-1.06zM18 10a.75.75 0 01-.75.75h-1.5a.75.75 0 010-1.5h1.5A.75.75 0 0118 10zM5 10a.75.75 0 01-.75.75h-1.5a.75.75 0 010-1.5h1.5A.75.75 0 015 10zM14.596 15.657a.75.75 0 001.06-1.06l-1.06-1.061a.75.75 0 10-1.06 1.06l1.06 1.06zM5.404 6.464a.75.75 0 001.06-1.06l-1.06-1.06a.75.75 0 10-1.061 1.06l1.06 1.06z"
/> />
</svg> --> </svg> -->
<span class="ml-2 self-center"> JSON </span> <span class="ml-2 self-center">{$i18n.t(' JSON ')}</span>
{/if} {/if}
</button> </button>
</div> </div>

View file

@ -1,4 +1,8 @@
<script lang="ts"> <script lang="ts">
import { getContext } from 'svelte';
const i18n = getContext('i18n');
export let options = { export let options = {
// Advanced // Advanced
seed: 0, seed: 0,
@ -20,7 +24,7 @@
<div class=" space-y-3 text-xs"> <div class=" space-y-3 text-xs">
<div> <div>
<div class=" py-0.5 flex w-full justify-between"> <div class=" py-0.5 flex w-full justify-between">
<div class=" w-20 text-xs font-medium self-center">Seed</div> <div class=" w-20 text-xs font-medium self-center">{$i18n.t('Seed')}</div>
<div class=" flex-1 self-center"> <div class=" flex-1 self-center">
<input <input
class="w-full rounded py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none border border-gray-100 dark:border-gray-600" class="w-full rounded py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none border border-gray-100 dark:border-gray-600"
@ -36,7 +40,7 @@
<div> <div>
<div class=" py-0.5 flex w-full justify-between"> <div class=" py-0.5 flex w-full justify-between">
<div class=" w-20 text-xs font-medium self-center">Stop Sequence</div> <div class=" w-20 text-xs font-medium self-center">{$i18n.t('Stop Sequence')}</div>
<div class=" flex-1 self-center"> <div class=" flex-1 self-center">
<input <input
class="w-full rounded py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none border border-gray-100 dark:border-gray-600" class="w-full rounded py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none border border-gray-100 dark:border-gray-600"
@ -51,7 +55,7 @@
<div class=" py-0.5 w-full justify-between"> <div class=" py-0.5 w-full justify-between">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">Temperature</div> <div class=" self-center text-xs font-medium">{$i18n.t('Temperature')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -61,9 +65,9 @@
}} }}
> >
{#if options.temperature === ''} {#if options.temperature === ''}
<span class="ml-2 self-center"> Default </span> <span class="ml-2 self-center"> {$i18n.t('Default')} </span>
{:else} {:else}
<span class="ml-2 self-center"> Custom </span> <span class="ml-2 self-center"> {$i18n.t('Custom')} </span>
{/if} {/if}
</button> </button>
</div> </div>
@ -97,7 +101,7 @@
<div class=" py-0.5 w-full justify-between"> <div class=" py-0.5 w-full justify-between">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">Mirostat</div> <div class=" self-center text-xs font-medium">{$i18n.t('Mirostat')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -107,9 +111,9 @@
}} }}
> >
{#if options.mirostat === ''} {#if options.mirostat === ''}
<span class="ml-2 self-center"> Default </span> <span class="ml-2 self-center">{$i18n.t(' Default ')}</span>
{:else} {:else}
<span class="ml-2 self-center"> Custom </span> <span class="ml-2 self-center">{$i18n.t(' Custom ')}</span>
{/if} {/if}
</button> </button>
</div> </div>
@ -143,7 +147,7 @@
<div class=" py-0.5 w-full justify-between"> <div class=" py-0.5 w-full justify-between">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">Mirostat Eta</div> <div class=" self-center text-xs font-medium">{$i18n.t('Mirostat Eta')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -153,9 +157,9 @@
}} }}
> >
{#if options.mirostat_eta === ''} {#if options.mirostat_eta === ''}
<span class="ml-2 self-center"> Default </span> <span class="ml-2 self-center">{$i18n.t(' Default ')}</span>
{:else} {:else}
<span class="ml-2 self-center"> Custom </span> <span class="ml-2 self-center">{$i18n.t(' Custom ')}</span>
{/if} {/if}
</button> </button>
</div> </div>
@ -189,7 +193,7 @@
<div class=" py-0.5 w-full justify-between"> <div class=" py-0.5 w-full justify-between">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">Mirostat Tau</div> <div class=" self-center text-xs font-medium">{$i18n.t('Mirostat Tau')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -199,9 +203,9 @@
}} }}
> >
{#if options.mirostat_tau === ''} {#if options.mirostat_tau === ''}
<span class="ml-2 self-center"> Default </span> <span class="ml-2 self-center">{$i18n.t(' Default ')}</span>
{:else} {:else}
<span class="ml-2 self-center"> Custom </span> <span class="ml-2 self-center">{$i18n.t(' Custom ')}</span>
{/if} {/if}
</button> </button>
</div> </div>
@ -235,7 +239,7 @@
<div class=" py-0.5 w-full justify-between"> <div class=" py-0.5 w-full justify-between">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">Top K</div> <div class=" self-center text-xs font-medium">{$i18n.t('Top K')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -245,9 +249,9 @@
}} }}
> >
{#if options.top_k === ''} {#if options.top_k === ''}
<span class="ml-2 self-center"> Default </span> <span class="ml-2 self-center">{$i18n.t(' Default ')}</span>
{:else} {:else}
<span class="ml-2 self-center"> Custom </span> <span class="ml-2 self-center">{$i18n.t(' Custom ')}</span>
{/if} {/if}
</button> </button>
</div> </div>
@ -281,7 +285,7 @@
<div class=" py-0.5 w-full justify-between"> <div class=" py-0.5 w-full justify-between">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">Top P</div> <div class=" self-center text-xs font-medium">{$i18n.t('Top P')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -291,9 +295,9 @@
}} }}
> >
{#if options.top_p === ''} {#if options.top_p === ''}
<span class="ml-2 self-center"> Default </span> <span class="ml-2 self-center">{$i18n.t(' Default ')}</span>
{:else} {:else}
<span class="ml-2 self-center"> Custom </span> <span class="ml-2 self-center">{$i18n.t(' Custom ')}</span>
{/if} {/if}
</button> </button>
</div> </div>
@ -327,7 +331,7 @@
<div class=" py-0.5 w-full justify-between"> <div class=" py-0.5 w-full justify-between">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">Repeat Penalty</div> <div class=" self-center text-xs font-medium">{$i18n.t('Repeat Penalty')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -337,9 +341,9 @@
}} }}
> >
{#if options.repeat_penalty === ''} {#if options.repeat_penalty === ''}
<span class="ml-2 self-center"> Default </span> <span class="ml-2 self-center">{$i18n.t(' Default ')}</span>
{:else} {:else}
<span class="ml-2 self-center"> Custom </span> <span class="ml-2 self-center">{$i18n.t(' Custom ')}</span>
{/if} {/if}
</button> </button>
</div> </div>
@ -373,7 +377,7 @@
<div class=" py-0.5 w-full justify-between"> <div class=" py-0.5 w-full justify-between">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">Repeat Last N</div> <div class=" self-center text-xs font-medium">{$i18n.t('Repeat Last N')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -383,9 +387,9 @@
}} }}
> >
{#if options.repeat_last_n === ''} {#if options.repeat_last_n === ''}
<span class="ml-2 self-center"> Default </span> <span class="ml-2 self-center">{$i18n.t(' Default ')}</span>
{:else} {:else}
<span class="ml-2 self-center"> Custom </span> <span class="ml-2 self-center">{$i18n.t(' Custom ')}</span>
{/if} {/if}
</button> </button>
</div> </div>
@ -419,7 +423,7 @@
<div class=" py-0.5 w-full justify-between"> <div class=" py-0.5 w-full justify-between">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">Tfs Z</div> <div class=" self-center text-xs font-medium">{$i18n.t('Tfs Z')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -429,9 +433,9 @@
}} }}
> >
{#if options.tfs_z === ''} {#if options.tfs_z === ''}
<span class="ml-2 self-center"> Default </span> <span class="ml-2 self-center">{$i18n.t(' Default ')}</span>
{:else} {:else}
<span class="ml-2 self-center"> Custom </span> <span class="ml-2 self-center">{$i18n.t(' Custom ')}</span>
{/if} {/if}
</button> </button>
</div> </div>
@ -465,7 +469,7 @@
<div class=" py-0.5 w-full justify-between"> <div class=" py-0.5 w-full justify-between">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">Context Length</div> <div class=" self-center text-xs font-medium">{$i18n.t('Context Length')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -475,9 +479,9 @@
}} }}
> >
{#if options.num_ctx === ''} {#if options.num_ctx === ''}
<span class="ml-2 self-center"> Default </span> <span class="ml-2 self-center">{$i18n.t(' Default ')}</span>
{:else} {:else}
<span class="ml-2 self-center"> Custom </span> <span class="ml-2 self-center">{$i18n.t(' Custom ')}</span>
{/if} {/if}
</button> </button>
</div> </div>
@ -510,7 +514,7 @@
</div> </div>
<div class=" py-0.5 w-full justify-between"> <div class=" py-0.5 w-full justify-between">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">Max Tokens</div> <div class=" self-center text-xs font-medium">{$i18n.t('Max Tokens')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -520,9 +524,9 @@
}} }}
> >
{#if options.num_predict === ''} {#if options.num_predict === ''}
<span class="ml-2 self-center"> Default </span> <span class="ml-2 self-center">{$i18n.t(' Default ')}</span>
{:else} {:else}
<span class="ml-2 self-center"> Custom </span> <span class="ml-2 self-center">{$i18n.t(' Custom ')}</span>
{/if} {/if}
</button> </button>
</div> </div>

View file

@ -1,8 +1,10 @@
<script lang="ts"> <script lang="ts">
import { createEventDispatcher, onMount } from 'svelte'; import { createEventDispatcher, onMount, getContext } from 'svelte';
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
const i18n = getContext('i18n');
export let saveSettings: Function; export let saveSettings: Function;
// Audio // Audio
@ -101,10 +103,10 @@
> >
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80"> <div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80">
<div> <div>
<div class=" mb-1 text-sm font-medium">STT Settings</div> <div class=" mb-1 text-sm font-medium">{$i18n.t('STT Settings')}</div>
<div class=" py-0.5 flex w-full justify-between"> <div class=" py-0.5 flex w-full justify-between">
<div class=" self-center text-xs font-medium">Speech-to-Text Engine</div> <div class=" self-center text-xs font-medium">{$i18n.t('Speech-to-Text Engine')}</div>
<div class="flex items-center relative"> <div class="flex items-center relative">
<select <select
class="w-fit pr-8 rounded px-2 p-1 text-xs bg-transparent outline-none text-right" class="w-fit pr-8 rounded px-2 p-1 text-xs bg-transparent outline-none text-right"
@ -119,14 +121,14 @@
} }
}} }}
> >
<option value="">Default (Web API)</option> <option value="">{$i18n.t('Default (Web API)')}</option>
<option value="whisper-local">Whisper (Local)</option> <option value="whisper-local">{$i18n.t('Whisper (Local)')}</option>
</select> </select>
</div> </div>
</div> </div>
<div class=" py-0.5 flex w-full justify-between"> <div class=" py-0.5 flex w-full justify-between">
<div class=" self-center text-xs font-medium">Conversation Mode</div> <div class=" self-center text-xs font-medium">{$i18n.t('Conversation Mode')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -136,15 +138,17 @@
type="button" type="button"
> >
{#if conversationMode === true} {#if conversationMode === true}
<span class="ml-2 self-center">On</span> <span class="ml-2 self-center">{$i18n.t('On')}</span>
{:else} {:else}
<span class="ml-2 self-center">Off</span> <span class="ml-2 self-center">{$i18n.t('Off')}</span>
{/if} {/if}
</button> </button>
</div> </div>
<div class=" py-0.5 flex w-full justify-between"> <div class=" py-0.5 flex w-full justify-between">
<div class=" self-center text-xs font-medium">Auto-send input after 3 sec.</div> <div class=" self-center text-xs font-medium">
{$i18n.t('Auto-send input after 3 sec.')}
</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -154,19 +158,19 @@
type="button" type="button"
> >
{#if speechAutoSend === true} {#if speechAutoSend === true}
<span class="ml-2 self-center">On</span> <span class="ml-2 self-center">{$i18n.t('On')}</span>
{:else} {:else}
<span class="ml-2 self-center">Off</span> <span class="ml-2 self-center">{$i18n.t('Off')}</span>
{/if} {/if}
</button> </button>
</div> </div>
</div> </div>
<div> <div>
<div class=" mb-1 text-sm font-medium">TTS Settings</div> <div class=" mb-1 text-sm font-medium">{$i18n.t('TTS Settings')}</div>
<div class=" py-0.5 flex w-full justify-between"> <div class=" py-0.5 flex w-full justify-between">
<div class=" self-center text-xs font-medium">Text-to-Speech Engine</div> <div class=" self-center text-xs font-medium">{$i18n.t('Text-to-Speech Engine')}</div>
<div class="flex items-center relative"> <div class="flex items-center relative">
<select <select
class="w-fit pr-8 rounded px-2 p-1 text-xs bg-transparent outline-none text-right" class="w-fit pr-8 rounded px-2 p-1 text-xs bg-transparent outline-none text-right"
@ -182,14 +186,14 @@
} }
}} }}
> >
<option value="">Default (Web API)</option> <option value="">{$i18n.t('Default (Web API)')}</option>
<option value="openai">Open AI</option> <option value="openai">{$i18n.t('Open AI')}</option>
</select> </select>
</div> </div>
</div> </div>
<div class=" py-0.5 flex w-full justify-between"> <div class=" py-0.5 flex w-full justify-between">
<div class=" self-center text-xs font-medium">Auto-playback response</div> <div class=" self-center text-xs font-medium">{$i18n.t('Auto-playback response')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -199,9 +203,9 @@
type="button" type="button"
> >
{#if responseAutoPlayback === true} {#if responseAutoPlayback === true}
<span class="ml-2 self-center">On</span> <span class="ml-2 self-center">{$i18n.t('On')}</span>
{:else} {:else}
<span class="ml-2 self-center">Off</span> <span class="ml-2 self-center">{$i18n.t('Off')}</span>
{/if} {/if}
</button> </button>
</div> </div>
@ -211,7 +215,7 @@
{#if TTSEngine === ''} {#if TTSEngine === ''}
<div> <div>
<div class=" mb-2.5 text-sm font-medium">Set Voice</div> <div class=" mb-2.5 text-sm font-medium">{$i18n.t('Set Voice')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1"> <div class="flex-1">
<select <select
@ -230,7 +234,7 @@
</div> </div>
{:else if TTSEngine === 'openai'} {:else if TTSEngine === 'openai'}
<div> <div>
<div class=" mb-2.5 text-sm font-medium">Set Voice</div> <div class=" mb-2.5 text-sm font-medium">{$i18n.t('Set Voice')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1"> <div class="flex-1">
<select <select

View file

@ -13,10 +13,12 @@
getChatList getChatList
} from '$lib/apis/chats'; } from '$lib/apis/chats';
import { getImportOrigin, convertOpenAIChats } from '$lib/utils'; import { getImportOrigin, convertOpenAIChats } from '$lib/utils';
import { onMount } from 'svelte'; import { onMount, getContext } from 'svelte';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
const i18n = getContext('i18n');
export let saveSettings: Function; export let saveSettings: Function;
// Chats // Chats
let saveChatHistory = true; let saveChatHistory = true;
@ -104,7 +106,7 @@
class="flex flex-col justify-between rounded-md items-center py-2 px-3.5 w-full transition" class="flex flex-col justify-between rounded-md items-center py-2 px-3.5 w-full transition"
> >
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-sm font-medium">Chat History</div> <div class=" self-center text-sm font-medium">{$i18n.t('Chat History')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -128,7 +130,7 @@
/> />
</svg> </svg>
<span class="ml-2 self-center"> On </span> <span class="ml-2 self-center"> {$i18n.t('On')} </span>
{:else} {:else}
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@ -146,7 +148,7 @@
/> />
</svg> </svg>
<span class="ml-2 self-center">Off</span> <span class="ml-2 self-center">{$i18n.t('Off')}</span>
{/if} {/if}
</button> </button>
</div> </div>
@ -180,7 +182,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center text-sm font-medium">Import Chats</div> <div class=" self-center text-sm font-medium">{$i18n.t('Import Chats')}</div>
</button> </button>
<button <button
class=" flex rounded-md py-2 px-3.5 w-full hover:bg-gray-200 dark:hover:bg-gray-800 transition" class=" flex rounded-md py-2 px-3.5 w-full hover:bg-gray-200 dark:hover:bg-gray-800 transition"
@ -202,7 +204,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center text-sm font-medium">Export Chats</div> <div class=" self-center text-sm font-medium">{$i18n.t('Export Chats')}</div>
</button> </button>
</div> </div>
@ -288,7 +290,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center text-sm font-medium">Delete Chats</div> <div class=" self-center text-sm font-medium">{$i18n.t('Delete Chats')}</div>
</button> </button>
{/if} {/if}
@ -316,7 +318,9 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center text-sm font-medium">Export All Chats (All Users)</div> <div class=" self-center text-sm font-medium">
{$i18n.t('Export All Chats (All Users)')}
</div>
</button> </button>
<hr class=" dark:border-gray-700" /> <hr class=" dark:border-gray-700" />
@ -330,7 +334,7 @@
}); });
if (res) { if (res) {
toast.success('Success'); toast.success($i18n.t('Success'));
} }
}} }}
> >
@ -348,7 +352,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center text-sm font-medium">Reset Vector Storage</div> <div class=" self-center text-sm font-medium">{$i18n.t('Reset Vector Storage')}</div>
</button> </button>
{/if} {/if}
</div> </div>

View file

@ -1,12 +1,14 @@
<script lang="ts"> <script lang="ts">
import { models, user } from '$lib/stores'; import { models, user } from '$lib/stores';
import { createEventDispatcher, onMount } from 'svelte'; import { createEventDispatcher, onMount, getContext } from 'svelte';
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
import { getOllamaAPIUrl, getOllamaVersion, updateOllamaAPIUrl } from '$lib/apis/ollama'; import { getOllamaAPIUrl, getOllamaVersion, updateOllamaAPIUrl } from '$lib/apis/ollama';
import { getOpenAIKey, getOpenAIUrl, updateOpenAIKey, updateOpenAIUrl } from '$lib/apis/openai'; import { getOpenAIKey, getOpenAIUrl, updateOpenAIKey, updateOpenAIUrl } from '$lib/apis/openai';
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
const i18n = getContext('i18n');
export let getModels: Function; export let getModels: Function;
// External // External
@ -34,7 +36,7 @@
}); });
if (ollamaVersion) { if (ollamaVersion) {
toast.success('Server connection verified'); toast.success($i18n.t('Server connection verified'));
await models.set(await getModels()); await models.set(await getModels());
} }
}; };
@ -64,7 +66,7 @@
<div class=" space-y-3"> <div class=" space-y-3">
<div class="mt-2 space-y-2 pr-1.5"> <div class="mt-2 space-y-2 pr-1.5">
<div class="flex justify-between items-center text-sm"> <div class="flex justify-between items-center text-sm">
<div class=" font-medium">OpenAI API</div> <div class=" font-medium">{$i18n.t('OpenAI API')}</div>
<button <button
class=" text-xs font-medium text-gray-500" class=" text-xs font-medium text-gray-500"
type="button" type="button"
@ -76,7 +78,7 @@
{#if showOpenAI} {#if showOpenAI}
<div> <div>
<div class=" mb-2.5 text-sm font-medium">API Key</div> <div class=" mb-2.5 text-sm font-medium">{$i18n.t('API Key')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1"> <div class="flex-1">
<input <input
@ -90,7 +92,7 @@
</div> </div>
<div> <div>
<div class=" mb-2.5 text-sm font-medium">API Base URL</div> <div class=" mb-2.5 text-sm font-medium">{$i18n.t('API Base URL')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1"> <div class="flex-1">
<input <input
@ -114,7 +116,7 @@
<hr class=" dark:border-gray-700" /> <hr class=" dark:border-gray-700" />
<div> <div>
<div class=" mb-2.5 text-sm font-medium">Ollama API URL</div> <div class=" mb-2.5 text-sm font-medium">{$i18n.t('Ollama API URL')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1 mr-2"> <div class="flex-1 mr-2">
<input <input

View file

@ -91,10 +91,10 @@
<div class="flex flex-col h-full justify-between text-sm"> <div class="flex flex-col h-full justify-between text-sm">
<div class=" pr-1.5 overflow-y-scroll max-h-[20.5rem]"> <div class=" pr-1.5 overflow-y-scroll max-h-[20.5rem]">
<div class=""> <div class="">
<div class=" mb-1 text-sm font-medium">WebUI Settings</div> <div class=" mb-1 text-sm font-medium">{$i18n.t('WebUI Settings')}</div>
<div class=" py-0.5 flex w-full justify-between"> <div class=" py-0.5 flex w-full justify-between">
<div class=" self-center text-xs font-medium">Theme</div> <div class=" self-center text-xs font-medium">{$i18n.t('Theme')}</div>
<div class="flex items-center relative"> <div class="flex items-center relative">
<div class=" absolute right-16"> <div class=" absolute right-16">
{#if theme === 'dark'} {#if theme === 'dark'}
@ -146,16 +146,16 @@
console.log(theme); console.log(theme);
}} }}
> >
<option value="dark">Dark</option> <option value="dark">{$i18n.t('Dark')}</option>
<option value="light">Light</option> <option value="light">{$i18n.t('Light')}</option>
<option value="rose-pine dark">Rosé Pine</option> <option value="rose-pine dark">{$i18n.t('Rosé Pine')}</option>
<option value="rose-pine-dawn light">Rosé Pine Dawn</option> <option value="rose-pine-dawn light">{$i18n.t('Rosé Pine Dawn')}</option>
</select> </select>
</div> </div>
</div> </div>
<div class=" py-0.5 flex w-full justify-between"> <div class=" py-0.5 flex w-full justify-between">
<div class=" self-center text-xs font-medium">Language</div> <div class=" self-center text-xs font-medium">{$i18n.t('Language')}</div>
<div class="flex items-center relative"> <div class="flex items-center relative">
<select <select
class="w-fit pr-8 rounded py-2 px-2 text-xs bg-transparent outline-none text-right" class="w-fit pr-8 rounded py-2 px-2 text-xs bg-transparent outline-none text-right"
@ -175,7 +175,7 @@
<div> <div>
<div class=" py-0.5 flex w-full justify-between"> <div class=" py-0.5 flex w-full justify-between">
<div class=" self-center text-xs font-medium">Notification</div> <div class=" self-center text-xs font-medium">{$i18n.t('Notification')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -185,9 +185,9 @@
type="button" type="button"
> >
{#if notificationEnabled === true} {#if notificationEnabled === true}
<span class="ml-2 self-center">On</span> <span class="ml-2 self-center">{$i18n.t('On')}</span>
{:else} {:else}
<span class="ml-2 self-center">Off</span> <span class="ml-2 self-center">{$i18n.t('Off')}</span>
{/if} {/if}
</button> </button>
</div> </div>
@ -197,7 +197,7 @@
<hr class=" dark:border-gray-700 my-3" /> <hr class=" dark:border-gray-700 my-3" />
<div> <div>
<div class=" my-2.5 text-sm font-medium">System Prompt</div> <div class=" my-2.5 text-sm font-medium">{$i18n.t('System Prompt')}</div>
<textarea <textarea
bind:value={system} bind:value={system}
class="w-full rounded p-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none resize-none" class="w-full rounded p-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none resize-none"
@ -207,7 +207,7 @@
<div class="mt-2 space-y-3 pr-1.5"> <div class="mt-2 space-y-3 pr-1.5">
<div class="flex justify-between items-center text-sm"> <div class="flex justify-between items-center text-sm">
<div class=" font-medium">Advanced Parameters</div> <div class=" font-medium">{$i18n.t('Advanced Parameters')}</div>
<button <button
class=" text-xs font-medium text-gray-500" class=" text-xs font-medium text-gray-500"
type="button" type="button"
@ -223,7 +223,7 @@
<div class=" py-1 w-full justify-between"> <div class=" py-1 w-full justify-between">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">Keep Alive</div> <div class=" self-center text-xs font-medium">{$i18n.t('Keep Alive')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -233,9 +233,9 @@
}} }}
> >
{#if keepAlive === null} {#if keepAlive === null}
<span class="ml-2 self-center"> Default </span> <span class="ml-2 self-center"> {$i18n.t('Default')} </span>
{:else} {:else}
<span class="ml-2 self-center"> Custom </span> <span class="ml-2 self-center"> {$i18n.t('Custom')} </span>
{/if} {/if}
</button> </button>
</div> </div>
@ -254,7 +254,7 @@
<div> <div>
<div class=" py-1 flex w-full justify-between"> <div class=" py-1 flex w-full justify-between">
<div class=" self-center text-sm font-medium">Request Mode</div> <div class=" self-center text-sm font-medium">{$i18n.t('Request Mode')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -263,7 +263,7 @@
}} }}
> >
{#if requestFormat === ''} {#if requestFormat === ''}
<span class="ml-2 self-center"> Default </span> <span class="ml-2 self-center"> {$i18n.t('Default')} </span>
{:else if requestFormat === 'json'} {:else if requestFormat === 'json'}
<!-- <svg <!-- <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@ -275,7 +275,7 @@
d="M10 2a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5A.75.75 0 0110 2zM10 15a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5A.75.75 0 0110 15zM10 7a3 3 0 100 6 3 3 0 000-6zM15.657 5.404a.75.75 0 10-1.06-1.06l-1.061 1.06a.75.75 0 001.06 1.06l1.06-1.06zM6.464 14.596a.75.75 0 10-1.06-1.06l-1.06 1.06a.75.75 0 001.06 1.06l1.06-1.06zM18 10a.75.75 0 01-.75.75h-1.5a.75.75 0 010-1.5h1.5A.75.75 0 0118 10zM5 10a.75.75 0 01-.75.75h-1.5a.75.75 0 010-1.5h1.5A.75.75 0 015 10zM14.596 15.657a.75.75 0 001.06-1.06l-1.06-1.061a.75.75 0 10-1.06 1.06l1.06 1.06zM5.404 6.464a.75.75 0 001.06-1.06l-1.06-1.06a.75.75 0 10-1.061 1.06l1.06 1.06z" d="M10 2a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5A.75.75 0 0110 2zM10 15a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5A.75.75 0 0110 15zM10 7a3 3 0 100 6 3 3 0 000-6zM15.657 5.404a.75.75 0 10-1.06-1.06l-1.061 1.06a.75.75 0 001.06 1.06l1.06-1.06zM6.464 14.596a.75.75 0 10-1.06-1.06l-1.06 1.06a.75.75 0 001.06 1.06l1.06-1.06zM18 10a.75.75 0 01-.75.75h-1.5a.75.75 0 010-1.5h1.5A.75.75 0 0118 10zM5 10a.75.75 0 01-.75.75h-1.5a.75.75 0 010-1.5h1.5A.75.75 0 015 10zM14.596 15.657a.75.75 0 001.06-1.06l-1.06-1.061a.75.75 0 10-1.06 1.06l1.06 1.06zM5.404 6.464a.75.75 0 001.06-1.06l-1.06-1.06a.75.75 0 10-1.061 1.06l1.06 1.06z"
/> />
</svg> --> </svg> -->
<span class="ml-2 self-center"> JSON </span> <span class="ml-2 self-center"> {$i18n.t('JSON')} </span>
{/if} {/if}
</button> </button>
</div> </div>

View file

@ -58,7 +58,7 @@
await getModels(); await getModels();
if (models) { if (models) {
toast.success('Server connection verified'); toast.success($i18n.t('Server connection verified'));
} }
} else { } else {
AUTOMATIC1111_BASE_URL = await getAUTOMATIC1111Url(localStorage.token); AUTOMATIC1111_BASE_URL = await getAUTOMATIC1111Url(localStorage.token);
@ -117,11 +117,13 @@
> >
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-[20.5rem]"> <div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-[20.5rem]">
<div> <div>
<div class=" mb-1 text-sm font-medium">Image Settings</div> <div class=" mb-1 text-sm font-medium">{$i18n.t('Image Settings')}</div>
<div> <div>
<div class=" py-0.5 flex w-full justify-between"> <div class=" py-0.5 flex w-full justify-between">
<div class=" self-center text-xs font-medium">Image Generation (Experimental)</div> <div class=" self-center text-xs font-medium">
{$i18n.t('Image Generation (Experimental)')}
</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -131,9 +133,9 @@
type="button" type="button"
> >
{#if enableImageGeneration === true} {#if enableImageGeneration === true}
<span class="ml-2 self-center">On</span> <span class="ml-2 self-center">{$i18n.t('On')}</span>
{:else} {:else}
<span class="ml-2 self-center">Off</span> <span class="ml-2 self-center">{$i18n.t('Off')}</span>
{/if} {/if}
</button> </button>
</div> </div>
@ -141,7 +143,7 @@
</div> </div>
<hr class=" dark:border-gray-700" /> <hr class=" dark:border-gray-700" />
<div class=" mb-2.5 text-sm font-medium">AUTOMATIC1111 Base URL</div> <div class=" mb-2.5 text-sm font-medium">{$i18n.t('AUTOMATIC1111 Base URL')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1 mr-2"> <div class="flex-1 mr-2">
<input <input
@ -189,7 +191,7 @@
<hr class=" dark:border-gray-700" /> <hr class=" dark:border-gray-700" />
<div> <div>
<div class=" mb-2.5 text-sm font-medium">Set Default Model</div> <div class=" mb-2.5 text-sm font-medium">{$i18n.t('Set Default Model')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1 mr-2"> <div class="flex-1 mr-2">
<select <select
@ -211,7 +213,7 @@
</div> </div>
<div> <div>
<div class=" mb-2.5 text-sm font-medium">Set Image Size</div> <div class=" mb-2.5 text-sm font-medium">{$i18n.t('Set Image Size')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1 mr-2"> <div class="flex-1 mr-2">
<input <input
@ -224,7 +226,7 @@
</div> </div>
<div> <div>
<div class=" mb-2.5 text-sm font-medium">Set Steps</div> <div class=" mb-2.5 text-sm font-medium">{$i18n.t('Set Steps')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1 mr-2"> <div class="flex-1 mr-2">
<input <input

View file

@ -96,11 +96,11 @@
> >
<div class=" space-y-3 pr-1.5 overflow-y-scroll h-80"> <div class=" space-y-3 pr-1.5 overflow-y-scroll h-80">
<div> <div>
<div class=" mb-1 text-sm font-medium">WebUI Add-ons</div> <div class=" mb-1 text-sm font-medium">{$i18n.t('WebUI Add-ons')}</div>
<div> <div>
<div class=" py-0.5 flex w-full justify-between"> <div class=" py-0.5 flex w-full justify-between">
<div class=" self-center text-xs font-medium">Title Auto-Generation</div> <div class=" self-center text-xs font-medium">{$i18n.t('Title Auto-Generation')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -110,9 +110,9 @@
type="button" type="button"
> >
{#if titleAutoGenerate === true} {#if titleAutoGenerate === true}
<span class="ml-2 self-center">On</span> <span class="ml-2 self-center">{$i18n.t('On')}</span>
{:else} {:else}
<span class="ml-2 self-center">Off</span> <span class="ml-2 self-center">{$i18n.t('Off')}</span>
{/if} {/if}
</button> </button>
</div> </div>
@ -120,7 +120,7 @@
<div> <div>
<div class=" py-0.5 flex w-full justify-between"> <div class=" py-0.5 flex w-full justify-between">
<div class=" self-center text-xs font-medium">Response AutoCopy to Clipboard</div> <div class=" self-center text-xs font-medium">{$i18n.t('Response AutoCopy to Clipboard')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -130,9 +130,9 @@
type="button" type="button"
> >
{#if responseAutoCopy === true} {#if responseAutoCopy === true}
<span class="ml-2 self-center">On</span> <span class="ml-2 self-center">{$i18n.t('On')}</span>
{:else} {:else}
<span class="ml-2 self-center">Off</span> <span class="ml-2 self-center">{$i18n.t('Off')}</span>
{/if} {/if}
</button> </button>
</div> </div>
@ -140,7 +140,7 @@
<div> <div>
<div class=" py-0.5 flex w-full justify-between"> <div class=" py-0.5 flex w-full justify-between">
<div class=" self-center text-xs font-medium">Full Screen Mode</div> <div class=" self-center text-xs font-medium">{$i18n.t('Full Screen Mode')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -150,9 +150,9 @@
type="button" type="button"
> >
{#if fullScreenMode === true} {#if fullScreenMode === true}
<span class="ml-2 self-center">On</span> <span class="ml-2 self-center">{$i18n.t('On')}</span>
{:else} {:else}
<span class="ml-2 self-center">Off</span> <span class="ml-2 self-center">{$i18n.t('Off')}</span>
{/if} {/if}
</button> </button>
</div> </div>
@ -172,9 +172,9 @@
type="button" type="button"
> >
{#if showUsername === true} {#if showUsername === true}
<span class="ml-2 self-center">On</span> <span class="ml-2 self-center">{$i18n.t('On')}</span>
{:else} {:else}
<span class="ml-2 self-center">Off</span> <span class="ml-2 self-center">{$i18n.t('Off')}</span>
{/if} {/if}
</button> </button>
</div> </div>
@ -184,7 +184,7 @@
<hr class=" dark:border-gray-700" /> <hr class=" dark:border-gray-700" />
<div> <div>
<div class=" mb-2.5 text-sm font-medium">Set Title Auto-Generation Model</div> <div class=" mb-2.5 text-sm font-medium">{$i18n.t('Set Title Auto-Generation Model')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1 mr-2"> <div class="flex-1 mr-2">
<select <select
@ -227,7 +227,7 @@
</button> </button>
</div> </div>
<div class="mt-3"> <div class="mt-3">
<div class=" mb-2.5 text-sm font-medium">Title Generation Prompt</div> <div class=" mb-2.5 text-sm font-medium">{$i18n.t('Title Generation Prompt')}</div>
<textarea <textarea
bind:value={titleGenerationPrompt} bind:value={titleGenerationPrompt}
class="w-full rounded p-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none resize-none" class="w-full rounded p-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none resize-none"
@ -241,7 +241,7 @@
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80"> <div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80">
<div class="flex w-full justify-between mb-2"> <div class="flex w-full justify-between mb-2">
<div class=" self-center text-sm font-semibold">Default Prompt Suggestions</div> <div class=" self-center text-sm font-semibold">{$i18n.t('Default Prompt Suggestions')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"

View file

@ -78,7 +78,7 @@
if (!data.success) { if (!data.success) {
toast.error(data.error); toast.error(data.error);
} else { } else {
toast.success(`Model '${modelName}' has been successfully downloaded.`); toast.success($i18n.t(`Model '${modelName}' has been successfully downloaded.`));
const notification = new Notification($WEBUI_NAME, { const notification = new Notification($WEBUI_NAME, {
body: `Model '${modelName}' has been successfully downloaded.`, body: `Model '${modelName}' has been successfully downloaded.`,
@ -243,7 +243,7 @@
}); });
if (res) { if (res) {
toast.success(`Deleted ${deleteModelTag}`); toast.success($i18n.t(`Deleted ${deleteModelTag}`));
} }
deleteModelTag = ''; deleteModelTag = '';
@ -372,7 +372,7 @@
<div> <div>
<div class=" mb-2 text-sm font-medium">Manage Ollama Models</div> <div class=" mb-2 text-sm font-medium">Manage Ollama Models</div>
<div class=" mb-2 text-sm font-medium">Pull a model from Ollama.com</div> <div class=" mb-2 text-sm font-medium">{$i18n.t('Pull a model from Ollama.com')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1 mr-2"> <div class="flex-1 mr-2">
<input <input
@ -436,7 +436,7 @@
To access the available model names for downloading, <a To access the available model names for downloading, <a
class=" text-gray-500 dark:text-gray-300 font-medium underline" class=" text-gray-500 dark:text-gray-300 font-medium underline"
href="https://ollama.com/library" href="https://ollama.com/library"
target="_blank">click here.</a target="_blank">{$i18n.t('click here.')}</a
> >
</div> </div>
@ -461,7 +461,7 @@
</div> </div>
<div> <div>
<div class=" mb-2 text-sm font-medium">Delete a model</div> <div class=" mb-2 text-sm font-medium">{$i18n.t('Delete a model')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1 mr-2"> <div class="flex-1 mr-2">
<select <select
@ -503,7 +503,7 @@
<div> <div>
<div class="flex justify-between items-center text-xs"> <div class="flex justify-between items-center text-xs">
<div class=" text-sm font-medium">Experimental</div> <div class=" text-sm font-medium">{$i18n.t('Experimental')}</div>
<button <button
class=" text-xs font-medium text-gray-500" class=" text-xs font-medium text-gray-500"
type="button" type="button"
@ -521,7 +521,7 @@
}} }}
> >
<div class=" mb-2 flex w-full justify-between"> <div class=" mb-2 flex w-full justify-between">
<div class=" text-sm font-medium">Upload a GGUF model</div> <div class=" text-sm font-medium">{$i18n.t('Upload a GGUF model')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -535,9 +535,9 @@
type="button" type="button"
> >
{#if modelUploadMode === 'file'} {#if modelUploadMode === 'file'}
<span class="ml-2 self-center">File Mode</span> <span class="ml-2 self-center">{$i18n.t('File Mode')}</span>
{:else} {:else}
<span class="ml-2 self-center">URL Mode</span> <span class="ml-2 self-center">{$i18n.t('URL Mode')}</span>
{/if} {/if}
</button> </button>
</div> </div>
@ -642,7 +642,7 @@
{#if (modelUploadMode === 'file' && modelInputFile && modelInputFile.length > 0) || (modelUploadMode === 'url' && modelFileUrl !== '')} {#if (modelUploadMode === 'file' && modelInputFile && modelInputFile.length > 0) || (modelUploadMode === 'url' && modelFileUrl !== '')}
<div> <div>
<div> <div>
<div class=" my-2.5 text-sm font-medium">Modelfile Content</div> <div class=" my-2.5 text-sm font-medium">{$i18n.t('Modelfile Content')}</div>
<textarea <textarea
bind:value={modelFileContent} bind:value={modelFileContent}
class="w-full rounded py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none resize-none" class="w-full rounded py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none resize-none"
@ -655,13 +655,13 @@
To access the GGUF models available for downloading, <a To access the GGUF models available for downloading, <a
class=" text-gray-500 dark:text-gray-300 font-medium underline" class=" text-gray-500 dark:text-gray-300 font-medium underline"
href="https://huggingface.co/models?search=gguf" href="https://huggingface.co/models?search=gguf"
target="_blank">click here.</a target="_blank">{$i18n.t('click here.')}</a
> >
</div> </div>
{#if uploadProgress !== null} {#if uploadProgress !== null}
<div class="mt-2"> <div class="mt-2">
<div class=" mb-2 text-xs">Upload Progress</div> <div class=" mb-2 text-xs">{$i18n.t('Upload Progress')}</div>
<div class="w-full rounded-full dark:bg-gray-800"> <div class="w-full rounded-full dark:bg-gray-800">
<div <div
@ -685,11 +685,11 @@
<div class=" space-y-3"> <div class=" space-y-3">
<div class="mt-2 space-y-3 pr-1.5"> <div class="mt-2 space-y-3 pr-1.5">
<div> <div>
<div class=" mb-2 text-sm font-medium">Manage LiteLLM Models</div> <div class=" mb-2 text-sm font-medium">{$i18n.t('Manage LiteLLM Models')}</div>
<div> <div>
<div class="flex justify-between items-center text-xs"> <div class="flex justify-between items-center text-xs">
<div class=" text-sm font-medium">Add a model</div> <div class=" text-sm font-medium">{$i18n.t('Add a model')}</div>
<button <button
class=" text-xs font-medium text-gray-500" class=" text-xs font-medium text-gray-500"
type="button" type="button"
@ -732,7 +732,7 @@
{#if showLiteLLMParams} {#if showLiteLLMParams}
<div> <div>
<div class=" mb-1.5 text-sm font-medium">Model Name</div> <div class=" mb-1.5 text-sm font-medium">{$i18n.t('Model Name')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1"> <div class="flex-1">
<input <input
@ -746,7 +746,7 @@
</div> </div>
<div> <div>
<div class=" mb-1.5 text-sm font-medium">API Base URL</div> <div class=" mb-1.5 text-sm font-medium">{$i18n.t('API Base URL')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1"> <div class="flex-1">
<input <input
@ -760,7 +760,7 @@
</div> </div>
<div> <div>
<div class=" mb-1.5 text-sm font-medium">API Key</div> <div class=" mb-1.5 text-sm font-medium">{$i18n.t('API Key')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1"> <div class="flex-1">
<input <input
@ -774,7 +774,7 @@
</div> </div>
<div> <div>
<div class="mb-1.5 text-sm font-medium">API RPM</div> <div class="mb-1.5 text-sm font-medium">{$i18n.t('API RPM')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1"> <div class="flex-1">
<input <input
@ -801,7 +801,7 @@
</div> </div>
<div> <div>
<div class=" mb-2.5 text-sm font-medium">Delete a model</div> <div class=" mb-2.5 text-sm font-medium">{$i18n.t('Delete a model')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1 mr-2"> <div class="flex-1 mr-2">
<select <select
@ -810,8 +810,7 @@
placeholder={$i18n.t('Select a model')} placeholder={$i18n.t('Select a model')}
> >
{#if !deleteLiteLLMModelId} {#if !deleteLiteLLMModelId}
<option value="" disabled selected>{$i18n.t('Select a model')}</option <option value="" disabled selected>{$i18n.t('Select a model')}</option>
>
{/if} {/if}
{#each liteLLMModelInfo as model} {#each liteLLMModelInfo as model}
<option value={model.model_info.id} class="bg-gray-100 dark:bg-gray-700" <option value={model.model_info.id} class="bg-gray-100 dark:bg-gray-700"
@ -846,7 +845,7 @@
<!-- <div class="mt-2 space-y-3 pr-1.5"> <!-- <div class="mt-2 space-y-3 pr-1.5">
<div> <div>
<div class=" mb-2.5 text-sm font-medium">Add LiteLLM Model</div> <div class=" mb-2.5 text-sm font-medium">{$i18n.t('Add LiteLLM Model')}</div>
<div class="flex w-full mb-2"> <div class="flex w-full mb-2">
<div class="flex-1"> <div class="flex-1">
<input <input
@ -859,7 +858,7 @@
</div> </div>
<div class="flex justify-between items-center text-sm"> <div class="flex justify-between items-center text-sm">
<div class=" font-medium">Advanced Model Params</div> <div class=" font-medium">{$i18n.t('Advanced Model Params')}</div>
<button <button
class=" text-xs font-medium text-gray-500" class=" text-xs font-medium text-gray-500"
type="button" type="button"
@ -871,7 +870,7 @@
{#if showLiteLLMParams} {#if showLiteLLMParams}
<div> <div>
<div class=" mb-2.5 text-sm font-medium">LiteLLM API Key</div> <div class=" mb-2.5 text-sm font-medium">{$i18n.t('LiteLLM API Key')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1"> <div class="flex-1">
<input <input
@ -885,7 +884,7 @@
</div> </div>
<div> <div>
<div class=" mb-2.5 text-sm font-medium">LiteLLM API Base URL</div> <div class=" mb-2.5 text-sm font-medium">{$i18n.t('LiteLLM API Base URL')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1"> <div class="flex-1">
<input <input
@ -899,7 +898,7 @@
</div> </div>
<div> <div>
<div class=" mb-2.5 text-sm font-medium">LiteLLM API RPM</div> <div class=" mb-2.5 text-sm font-medium">{$i18n.t('LiteLLM API RPM')}</div>
<div class="flex w-full"> <div class="flex w-full">
<div class="flex-1"> <div class="flex-1">
<input <input

View file

@ -1,4 +1,5 @@
<script lang="ts"> <script lang="ts">
import { getContext } from 'svelte';
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
import { models, settings, user } from '$lib/stores'; import { models, settings, user } from '$lib/stores';
@ -17,6 +18,8 @@
import Connections from './Settings/Connections.svelte'; import Connections from './Settings/Connections.svelte';
import Images from './Settings/Images.svelte'; import Images from './Settings/Images.svelte';
const i18n = getContext('i18n');
export let show = false; export let show = false;
const saveSettings = async (updated) => { const saveSettings = async (updated) => {
@ -58,7 +61,7 @@
<Modal bind:show> <Modal bind:show>
<div> <div>
<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> <div class=" flex justify-between dark:text-gray-300 px-5 py-4">
<div class=" text-lg font-medium self-center">Settings</div> <div class=" text-lg font-medium self-center">{$i18n.t('Settings')}</div>
<button <button
class="self-center" class="self-center"
on:click={() => { on:click={() => {
@ -106,7 +109,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center">General</div> <div class=" self-center">{$i18n.t('General')}</div>
</button> </button>
{#if $user?.role === 'admin'} {#if $user?.role === 'admin'}
@ -131,7 +134,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center">Connections</div> <div class=" self-center">{$i18n.t('Connections')}</div>
</button> </button>
<button <button
@ -157,7 +160,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center">Models</div> <div class=" self-center">{$i18n.t('Models')}</div>
</button> </button>
{/if} {/if}
@ -184,7 +187,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center">Interface</div> <div class=" self-center">{$i18n.t('Interface')}</div>
</button> </button>
<button <button
@ -211,7 +214,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center">Audio</div> <div class=" self-center">{$i18n.t('Audio')}</div>
</button> </button>
{#if $user.role === 'admin'} {#if $user.role === 'admin'}
@ -238,7 +241,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center">Images</div> <div class=" self-center">{$i18n.t('Images')}</div>
</button> </button>
{/if} {/if}
@ -265,7 +268,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center">Chats</div> <div class=" self-center">{$i18n.t('Chats')}</div>
</button> </button>
<button <button
@ -291,7 +294,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center">Account</div> <div class=" self-center">{$i18n.t('Account')}</div>
</button> </button>
<button <button
@ -317,7 +320,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center">About</div> <div class=" self-center">{$i18n.t('About')}</div>
</button> </button>
</div> </div>
<div class="flex-1 md:min-h-[380px]"> <div class="flex-1 md:min-h-[380px]">

View file

@ -1,6 +1,9 @@
<script lang="ts"> <script lang="ts">
import { getContext } from 'svelte';
import Modal from '../common/Modal.svelte'; import Modal from '../common/Modal.svelte';
const i18n = getContext('i18n');
export let downloadChat: Function; export let downloadChat: Function;
export let shareChat: Function; export let shareChat: Function;
@ -17,11 +20,11 @@
show = false; show = false;
}} }}
> >
Share to OpenWebUI Community {$i18n.t('Share to OpenWebUI Community')}
</button> </button>
<div class="flex justify-center space-x-1 mt-1.5"> <div class="flex justify-center space-x-1 mt-1.5">
<div class=" self-center text-gray-400 text-xs font-medium">or</div> <div class=" self-center text-gray-400 text-xs font-medium">{$i18n.t('or')}</div>
<button <button
class=" self-center rounded-full text-xs font-medium text-gray-700 dark:text-gray-500 underline" class=" self-center rounded-full text-xs font-medium text-gray-700 dark:text-gray-500 underline"
@ -31,7 +34,7 @@
show = false; show = false;
}} }}
> >
Download as a File {$i18n.t('Download as a File')}
</button> </button>
</div> </div>
</div> </div>

View file

@ -1,13 +1,16 @@
<script lang="ts"> <script lang="ts">
import { getContext } from 'svelte';
import Modal from '../common/Modal.svelte'; import Modal from '../common/Modal.svelte';
const i18n = getContext('i18n');
export let show = false; export let show = false;
</script> </script>
<Modal bind:show> <Modal bind:show>
<div> <div>
<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> <div class=" flex justify-between dark:text-gray-300 px-5 py-4">
<div class=" text-lg font-medium self-center">Keyboard shortcuts</div> <div class=" text-lg font-medium self-center">{$i18n.t('Keyboard shortcuts')}</div>
<button <button
class="self-center" class="self-center"
on:click={() => { on:click={() => {
@ -32,7 +35,7 @@
<div class=" flex flex-col w-full sm:flex-row sm:justify-center sm:space-x-6"> <div class=" flex flex-col w-full sm:flex-row sm:justify-center sm:space-x-6">
<div class="flex flex-col space-y-3 w-full self-start"> <div class="flex flex-col space-y-3 w-full self-start">
<div class="w-full flex justify-between items-center"> <div class="w-full flex justify-between items-center">
<div class=" text-sm">Open new chat</div> <div class=" text-sm">{$i18n.t('Open new chat')}</div>
<div class="flex space-x-1 text-xs"> <div class="flex space-x-1 text-xs">
<div <div
@ -56,7 +59,7 @@
</div> </div>
<div class="w-full flex justify-between items-center"> <div class="w-full flex justify-between items-center">
<div class=" text-sm">Focus chat input</div> <div class=" text-sm">{$i18n.t('Focus chat input')}</div>
<div class="flex space-x-1 text-xs"> <div class="flex space-x-1 text-xs">
<div <div
@ -74,7 +77,7 @@
</div> </div>
<div class="w-full flex justify-between items-center"> <div class="w-full flex justify-between items-center">
<div class=" text-sm">Copy last code block</div> <div class=" text-sm">{$i18n.t('Copy last code block')}</div>
<div class="flex space-x-1 text-xs"> <div class="flex space-x-1 text-xs">
<div <div
@ -98,7 +101,7 @@
</div> </div>
<div class="w-full flex justify-between items-center"> <div class="w-full flex justify-between items-center">
<div class=" text-sm">Copy last response</div> <div class=" text-sm">{$i18n.t('Copy last response')}</div>
<div class="flex space-x-1 text-xs"> <div class="flex space-x-1 text-xs">
<div <div
@ -124,7 +127,7 @@
<div class="flex flex-col space-y-3 w-full self-start"> <div class="flex flex-col space-y-3 w-full self-start">
<div class="w-full flex justify-between items-center"> <div class="w-full flex justify-between items-center">
<div class=" text-sm">Toggle settings</div> <div class=" text-sm">{$i18n.t('Toggle settings')}</div>
<div class="flex space-x-1 text-xs"> <div class="flex space-x-1 text-xs">
<div <div
@ -141,7 +144,7 @@
</div> </div>
<div class="w-full flex justify-between items-center"> <div class="w-full flex justify-between items-center">
<div class=" text-sm">Toggle sidebar</div> <div class=" text-sm">{$i18n.t('Toggle sidebar')}</div>
<div class="flex space-x-1 text-xs"> <div class="flex space-x-1 text-xs">
<div <div
@ -165,7 +168,7 @@
</div> </div>
<div class="w-full flex justify-between items-center"> <div class="w-full flex justify-between items-center">
<div class=" text-sm">Delete chat</div> <div class=" text-sm">{$i18n.t('Delete chat')}</div>
<div class="flex space-x-1 text-xs"> <div class="flex space-x-1 text-xs">
<div <div
@ -188,7 +191,7 @@
</div> </div>
<div class="w-full flex justify-between items-center"> <div class="w-full flex justify-between items-center">
<div class=" text-sm">Show shortcuts</div> <div class=" text-sm">{$i18n.t('Show shortcuts')}</div>
<div class="flex space-x-1 text-xs"> <div class="flex space-x-1 text-xs">
<div <div

View file

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { onMount } from 'svelte'; import { onMount, getContext } from 'svelte';
import { createNewDoc, getDocs, tagDocByName, updateDocByName } from '$lib/apis/documents'; import { createNewDoc, getDocs, tagDocByName, updateDocByName } from '$lib/apis/documents';
import Modal from '../common/Modal.svelte'; import Modal from '../common/Modal.svelte';
@ -13,6 +13,8 @@
import { transformFileName } from '$lib/utils'; import { transformFileName } from '$lib/utils';
import { SUPPORTED_FILE_EXTENSIONS, SUPPORTED_FILE_TYPE } from '$lib/constants'; import { SUPPORTED_FILE_EXTENSIONS, SUPPORTED_FILE_TYPE } from '$lib/constants';
const i18n = getContext('i18n');
export let show = false; export let show = false;
export let selectedDoc; export let selectedDoc;
@ -96,7 +98,7 @@
<Modal size="sm" bind:show> <Modal size="sm" bind:show>
<div> <div>
<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> <div class=" flex justify-between dark:text-gray-300 px-5 py-4">
<div class=" text-lg font-medium self-center">Add Docs</div> <div class=" text-lg font-medium self-center">{$i18n.t('Add Docs')}</div>
<button <button
class="self-center" class="self-center"
on:click={() => { on:click={() => {
@ -145,7 +147,7 @@
<div class=" flex flex-col space-y-1.5"> <div class=" flex flex-col space-y-1.5">
<div class="flex flex-col w-full"> <div class="flex flex-col w-full">
<div class=" mb-1.5 text-xs text-gray-500">Tags</div> <div class=" mb-1.5 text-xs text-gray-500">{$i18n.t('Tags')}</div>
<Tags {tags} addTag={addTagHandler} deleteTag={deleteTagHandler} /> <Tags {tags} addTag={addTagHandler} deleteTag={deleteTagHandler} />
</div> </div>

View file

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { onMount } from 'svelte'; import { onMount, getContext } from 'svelte';
import { getDocs, tagDocByName, updateDocByName } from '$lib/apis/documents'; import { getDocs, tagDocByName, updateDocByName } from '$lib/apis/documents';
import Modal from '../common/Modal.svelte'; import Modal from '../common/Modal.svelte';
@ -10,6 +10,8 @@
import Tags from '../common/Tags.svelte'; import Tags from '../common/Tags.svelte';
import { addTagById } from '$lib/apis/chats'; import { addTagById } from '$lib/apis/chats';
const i18n = getContext('i18n');
export let show = false; export let show = false;
export let selectedDoc; export let selectedDoc;
@ -74,7 +76,7 @@
<Modal size="sm" bind:show> <Modal size="sm" bind:show>
<div> <div>
<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> <div class=" flex justify-between dark:text-gray-300 px-5 py-4">
<div class=" text-lg font-medium self-center">Edit Doc</div> <div class=" text-lg font-medium self-center">{$i18n.t('Edit Doc')}</div>
<button <button
class="self-center" class="self-center"
on:click={() => { on:click={() => {
@ -105,7 +107,7 @@
> >
<div class=" flex flex-col space-y-1.5"> <div class=" flex flex-col space-y-1.5">
<div class="flex flex-col w-full"> <div class="flex flex-col w-full">
<div class=" mb-1 text-xs text-gray-500">Name Tag</div> <div class=" mb-1 text-xs text-gray-500">{$i18n.t('Name Tag')}</div>
<div class="flex flex-1"> <div class="flex flex-1">
<div <div
@ -134,7 +136,7 @@
</div> </div>
<div class="flex flex-col w-full"> <div class="flex flex-col w-full">
<div class=" mb-1 text-xs text-gray-500">Title</div> <div class=" mb-1 text-xs text-gray-500">{$i18n.t('Title')}</div>
<div class="flex-1"> <div class="flex-1">
<input <input
@ -148,7 +150,7 @@
</div> </div>
<div class="flex flex-col w-full"> <div class="flex flex-col w-full">
<div class=" mb-1.5 text-xs text-gray-500">Tags</div> <div class=" mb-1.5 text-xs text-gray-500">{$i18n.t('Tags')}</div>
<Tags {tags} addTag={addTagHandler} deleteTag={deleteTagHandler} /> <Tags {tags} addTag={addTagHandler} deleteTag={deleteTagHandler} />
</div> </div>

View file

@ -8,9 +8,11 @@
updateRAGTemplate updateRAGTemplate
} from '$lib/apis/rag'; } from '$lib/apis/rag';
import { documents } from '$lib/stores'; import { documents } from '$lib/stores';
import { onMount } from 'svelte'; import { onMount, getContext } from 'svelte';
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
const i18n = getContext('i18n');
export let saveHandler: Function; export let saveHandler: Function;
let loading = false; let loading = false;
@ -27,7 +29,7 @@
if (res) { if (res) {
await documents.set(await getDocs(localStorage.token)); await documents.set(await getDocs(localStorage.token));
toast.success('Scan complete!'); toast.success($i18n.t('Scan complete!'));
} }
}; };
@ -57,10 +59,12 @@
> >
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80"> <div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80">
<div> <div>
<div class=" mb-2 text-sm font-medium">General Settings</div> <div class=" mb-2 text-sm font-medium">{$i18n.t('General Settings')}</div>
<div class=" flex w-full justify-between"> <div class=" flex w-full justify-between">
<div class=" self-center text-xs font-medium">Scan for documents from '/data/docs'</div> <div class=" self-center text-xs font-medium">
{$i18n.t('Scan for documents from {{path}}', { path: '/data/docs' })}
</div>
<button <button
class=" self-center text-xs p-1 px-3 bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 rounded flex flex-row space-x-1 items-center {loading class=" self-center text-xs p-1 px-3 bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 rounded flex flex-row space-x-1 items-center {loading
@ -73,7 +77,7 @@
type="button" type="button"
disabled={loading} disabled={loading}
> >
<div class="self-center font-medium">Scan</div> <div class="self-center font-medium">{$i18n.t('Scan')}</div>
<!-- <svg <!-- <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@ -122,11 +126,11 @@
<hr class=" dark:border-gray-700" /> <hr class=" dark:border-gray-700" />
<div class=" "> <div class=" ">
<div class=" text-sm font-medium">Chunk Params</div> <div class=" text-sm font-medium">{$i18n.t('Chunk Params')}</div>
<div class=" flex"> <div class=" flex">
<div class=" flex w-full justify-between"> <div class=" flex w-full justify-between">
<div class="self-center text-xs font-medium min-w-fit">Chunk Size</div> <div class="self-center text-xs font-medium min-w-fit">{$i18n.t('Chunk Size')}</div>
<div class="self-center p-3"> <div class="self-center p-3">
<input <input
@ -141,7 +145,7 @@
</div> </div>
<div class="flex w-full"> <div class="flex w-full">
<div class=" self-center text-xs font-medium min-w-fit">Chunk Overlap</div> <div class=" self-center text-xs font-medium min-w-fit">{$i18n.t('Chunk Overlap')}</div>
<div class="self-center p-3"> <div class="self-center p-3">
<input <input
@ -157,7 +161,7 @@
</div> </div>
<div> <div>
<div class=" mb-2.5 text-sm font-medium">RAG Template</div> <div class=" mb-2.5 text-sm font-medium">{$i18n.t('RAG Template')}</div>
<textarea <textarea
bind:value={template} bind:value={template}
class="w-full rounded p-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none resize-none" class="w-full rounded p-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none resize-none"

View file

@ -1,7 +1,10 @@
<script> <script>
import { getContext } from 'svelte';
import Modal from '../common/Modal.svelte'; import Modal from '../common/Modal.svelte';
import General from './Settings/General.svelte'; import General from './Settings/General.svelte';
const i18n = getContext('i18n');
export let show = false; export let show = false;
let selectedTab = 'general'; let selectedTab = 'general';
@ -10,7 +13,7 @@
<Modal bind:show> <Modal bind:show>
<div> <div>
<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> <div class=" flex justify-between dark:text-gray-300 px-5 py-4">
<div class=" text-lg font-medium self-center">Document Settings</div> <div class=" text-lg font-medium self-center">{$i18n.t('Document Settings')}</div>
<button <button
class="self-center" class="self-center"
on:click={() => { on:click={() => {
@ -58,7 +61,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center">General</div> <div class=" self-center">{$i18n.t('General')}</div>
</button> </button>
</div> </div>
<div class="flex-1 md:min-h-[380px]"> <div class="flex-1 md:min-h-[380px]">

View file

@ -1,4 +1,5 @@
<script lang="ts"> <script lang="ts">
import { getContext } from 'svelte';
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
import fileSaver from 'file-saver'; import fileSaver from 'file-saver';
const { saveAs } = fileSaver; const { saveAs } = fileSaver;
@ -9,6 +10,8 @@
import TagInput from '../common/Tags/TagInput.svelte'; import TagInput from '../common/Tags/TagInput.svelte';
import Tags from '../common/Tags.svelte'; import Tags from '../common/Tags.svelte';
const i18n = getContext('i18n');
export let initNewChat: Function; export let initNewChat: Function;
export let title: string = $WEBUI_NAME; export let title: string = $WEBUI_NAME;
export let shareEnabled: boolean = false; export let shareEnabled: boolean = false;
@ -26,7 +29,7 @@
const chat = (await getChatById(localStorage.token, $chatId)).chat; const chat = (await getChatById(localStorage.token, $chatId)).chat;
console.log('share', chat); console.log('share', chat);
toast.success('Redirecting you to OpenWebUI Community'); toast.success($i18n.t('Redirecting you to OpenWebUI Community'));
const url = 'https://openwebui.com'; const url = 'https://openwebui.com';
// const url = 'http://localhost:5173'; // const url = 'http://localhost:5173';

View file

@ -7,8 +7,7 @@
import { goto, invalidateAll } from '$app/navigation'; import { goto, invalidateAll } from '$app/navigation';
import { page } from '$app/stores'; import { page } from '$app/stores';
import { user, chats, settings, showSettings, chatId, tags } from '$lib/stores'; import { user, chats, settings, showSettings, chatId, tags } from '$lib/stores';
import { onMount } from 'svelte'; import { onMount, getContext } from 'svelte';
import { getContext } from 'svelte';
const i18n = getContext('i18n'); const i18n = getContext('i18n');
@ -201,7 +200,7 @@
</div> </div>
<div class="flex self-center"> <div class="flex self-center">
<div class=" self-center font-medium text-sm">Prompts</div> <div class=" self-center font-medium text-sm">{$i18n.t('Prompts')}</div>
</div> </div>
</a> </a>
</div> </div>
@ -229,7 +228,7 @@
</div> </div>
<div class="flex self-center"> <div class="flex self-center">
<div class=" self-center font-medium text-sm">Documents</div> <div class=" self-center font-medium text-sm">{$i18n.t('Documents')}</div>
</div> </div>
</a> </a>
</div> </div>
@ -239,7 +238,7 @@
{#if !($settings.saveChatHistory ?? true)} {#if !($settings.saveChatHistory ?? true)}
<div class="absolute z-40 w-full h-full bg-black/90 flex justify-center"> <div class="absolute z-40 w-full h-full bg-black/90 flex justify-center">
<div class=" text-left px-5 py-2"> <div class=" text-left px-5 py-2">
<div class=" font-medium">Chat History is off for this browser.</div> <div class=" font-medium">{$i18n.t('Chat History is off for this browser.')}</div>
<div class="text-xs mt-2"> <div class="text-xs mt-2">
When history is turned off, new chats on this browser won't appear in your history on When history is turned off, new chats on this browser won't appear in your history on
any of your devices. <span class=" font-semibold" any of your devices. <span class=" font-semibold"
@ -596,7 +595,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center font-medium">Admin Panel</div> <div class=" self-center font-medium">{$i18n.t('Admin Panel')}</div>
</button> </button>
{/if} {/if}
@ -628,7 +627,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center font-medium">Settings</div> <div class=" self-center font-medium">{$i18n.t('Settings')}</div>
</button> </button>
</div> </div>
@ -662,7 +661,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center font-medium">Sign Out</div> <div class=" self-center font-medium">{$i18n.t('Sign Out')}</div>
</button> </button>
</div> </div>
</div> </div>

View file

@ -1,10 +1,10 @@
<script lang="ts"> <script lang="ts">
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
import { onMount, tick, getContext } from 'svelte';
import { openDB, deleteDB } from 'idb'; import { openDB, deleteDB } from 'idb';
import fileSaver from 'file-saver'; import fileSaver from 'file-saver';
const { saveAs } = fileSaver; const { saveAs } = fileSaver;
import { onMount, tick } from 'svelte';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { getOllamaModels, getOllamaVersion } from '$lib/apis/ollama'; import { getOllamaModels, getOllamaVersion } from '$lib/apis/ollama';
@ -35,6 +35,8 @@
import ShortcutsModal from '$lib/components/chat/ShortcutsModal.svelte'; import ShortcutsModal from '$lib/components/chat/ShortcutsModal.svelte';
import ChangelogModal from '$lib/components/ChangelogModal.svelte'; import ChangelogModal from '$lib/components/ChangelogModal.svelte';
const i18n = getContext('i18n');
let ollamaVersion = ''; let ollamaVersion = '';
let loaded = false; let loaded = false;
@ -266,12 +268,14 @@
</div> </div>
<div class=" mt-4 text-center text-sm dark:text-gray-200 w-full"> <div class=" mt-4 text-center text-sm dark:text-gray-200 w-full">
Saving chat logs directly to your browser's storage is no longer supported. Please {$i18n.t(
take a moment to download and delete your chat logs by clicking the button below. "Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through"
Don't worry, you can easily re-import your chat logs to the backend through <span )}
class="font-semibold dark:text-white">Settings > Chats > Import Chats</span <span class="font-semibold dark:text-white"
>. This ensures that your valuable conversations are securely saved to your backend >{$i18n.t('Settings')} > {$i18n.t('Chats')} > {$i18n.t('Import Chats')}</span
database. Thank you! >. {$i18n.t(
'This ensures that your valuable conversations are securely saved to your backend database. Thank you!'
)}
</div> </div>
<div class=" mt-6 mx-auto relative group w-fit"> <div class=" mt-6 mx-auto relative group w-fit">

View file

@ -2,7 +2,7 @@
import { WEBUI_API_BASE_URL } from '$lib/constants'; import { WEBUI_API_BASE_URL } from '$lib/constants';
import { WEBUI_NAME, config, user } from '$lib/stores'; import { WEBUI_NAME, config, user } from '$lib/stores';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { onMount } from 'svelte'; import { onMount, getContext } from 'svelte';
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
@ -11,6 +11,8 @@
import EditUserModal from '$lib/components/admin/EditUserModal.svelte'; import EditUserModal from '$lib/components/admin/EditUserModal.svelte';
import SettingsModal from '$lib/components/admin/SettingsModal.svelte'; import SettingsModal from '$lib/components/admin/SettingsModal.svelte';
const i18n = getContext('i18n');
let loaded = false; let loaded = false;
let users = []; let users = [];
@ -37,7 +39,7 @@
}); });
if (res) { if (res) {
users = await getUsers(localStorage.token); users = await getUsers(localStorage.token);
toast.success('Successfully updated'); toast.success($i18n.t('Successfully updated'));
} }
}; };
@ -115,7 +117,7 @@
/> />
</svg> </svg>
<div class=" text-xs">Admin Settings</div> <div class=" text-xs">{$i18n.t('Admin Settings')}</div>
</button> </button>
</div> </div>
</div> </div>
@ -131,10 +133,10 @@
class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400" class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400"
> >
<tr> <tr>
<th scope="col" class="px-3 py-2"> Role </th> <th scope="col" class="px-3 py-2"> {$i18n.t('Role')} </th>
<th scope="col" class="px-3 py-2"> Name </th> <th scope="col" class="px-3 py-2"> {$i18n.t('Name')} </th>
<th scope="col" class="px-3 py-2"> Email </th> <th scope="col" class="px-3 py-2"> {$i18n.t('Email')} </th>
<th scope="col" class="px-3 py-2"> Action </th> <th scope="col" class="px-3 py-2"> {$i18n.t('Action')} </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View file

@ -3,7 +3,7 @@
import fileSaver from 'file-saver'; import fileSaver from 'file-saver';
const { saveAs } = fileSaver; const { saveAs } = fileSaver;
import { onMount } from 'svelte'; import { onMount, getContext } from 'svelte';
import { WEBUI_NAME, documents } from '$lib/stores'; import { WEBUI_NAME, documents } from '$lib/stores';
import { createNewDoc, deleteDocByName, getDocs } from '$lib/apis/documents'; import { createNewDoc, deleteDocByName, getDocs } from '$lib/apis/documents';
@ -17,6 +17,9 @@
import AddFilesPlaceholder from '$lib/components/AddFilesPlaceholder.svelte'; import AddFilesPlaceholder from '$lib/components/AddFilesPlaceholder.svelte';
import SettingsModal from '$lib/components/documents/SettingsModal.svelte'; import SettingsModal from '$lib/components/documents/SettingsModal.svelte';
import AddDocModal from '$lib/components/documents/AddDocModal.svelte'; import AddDocModal from '$lib/components/documents/AddDocModal.svelte';
const i18n = getContext('i18n');
let importFiles = ''; let importFiles = '';
let inputFiles = ''; let inputFiles = '';
@ -188,7 +191,7 @@
<div class="max-w-2xl mx-auto w-full px-3 md:px-0 my-10"> <div class="max-w-2xl mx-auto w-full px-3 md:px-0 my-10">
<div class="mb-6"> <div class="mb-6">
<div class="flex justify-between items-center"> <div class="flex justify-between items-center">
<div class=" text-2xl font-semibold self-center">My Documents</div> <div class=" text-2xl font-semibold self-center">{$i18n.t('My Documents')}</div>
<div> <div>
<button <button
@ -211,7 +214,7 @@
/> />
</svg> </svg>
<div class=" text-xs">Document Settings</div> <div class=" text-xs">{$i18n.t('Document Settings')}</div>
</button> </button>
</div> </div>
</div> </div>
@ -274,7 +277,7 @@
on:dragleave={onDragLeave} on:dragleave={onDragLeave}
> >
<div class=" pointer-events-none"> <div class=" pointer-events-none">
<div class="text-center dark:text-white text-2xl font-semibold z-50">Add Files</div> <div class="text-center dark:text-white text-2xl font-semibold z-50">{$i18n.t('Add Files')}</div>
<div class=" mt-2 text-center text-sm dark:text-gray-200 w-full"> <div class=" mt-2 text-center text-sm dark:text-gray-200 w-full">
Drop any files here to add to my documents Drop any files here to add to my documents
@ -314,7 +317,7 @@
// await chats.set(await getChatListByTagName(localStorage.token, tag.name)); // await chats.set(await getChatListByTagName(localStorage.token, tag.name));
}} }}
> >
<div class=" text-xs font-medium self-center line-clamp-1">all</div> <div class=" text-xs font-medium self-center line-clamp-1">{$i18n.t('all')}</div>
</button> </button>
{#each tags as tag} {#each tags as tag}
@ -344,7 +347,7 @@
// await chats.set(await getChatListByTagName(localStorage.token, tag.name)); // await chats.set(await getChatListByTagName(localStorage.token, tag.name));
}} }}
> >
<div class=" text-xs font-medium self-center line-clamp-1">add tags</div> <div class=" text-xs font-medium self-center line-clamp-1">{$i18n.t('add tags')}</div>
</button> --> </button> -->
<button <button
@ -354,7 +357,9 @@
// await chats.set(await getChatListByTagName(localStorage.token, tag.name)); // await chats.set(await getChatListByTagName(localStorage.token, tag.name));
}} }}
> >
<div class=" text-xs font-medium self-center line-clamp-1">delete</div> <div class=" text-xs font-medium self-center line-clamp-1">
{$i18n.t('delete')}
</div>
</button> </button>
</div> </div>
</div> </div>
@ -562,7 +567,7 @@
document.getElementById('documents-import-input')?.click(); document.getElementById('documents-import-input')?.click();
}} }}
> >
<div class=" self-center mr-2 font-medium">Import Documents Mapping</div> <div class=" self-center mr-2 font-medium">{$i18n.t('Import Documents Mapping')}</div>
<div class=" self-center"> <div class=" self-center">
<svg <svg
@ -589,7 +594,7 @@
saveAs(blob, `documents-mapping-export-${Date.now()}.json`); saveAs(blob, `documents-mapping-export-${Date.now()}.json`);
}} }}
> >
<div class=" self-center mr-2 font-medium">Export Documents Mapping</div> <div class=" self-center mr-2 font-medium">{$i18n.t('Export Documents Mapping')}</div>
<div class=" self-center"> <div class=" self-center">
<svg <svg

View file

@ -3,7 +3,7 @@
import fileSaver from 'file-saver'; import fileSaver from 'file-saver';
const { saveAs } = fileSaver; const { saveAs } = fileSaver;
import { onMount } from 'svelte'; import { onMount, getContext } from 'svelte';
import { WEBUI_NAME, modelfiles, settings, user } from '$lib/stores'; import { WEBUI_NAME, modelfiles, settings, user } from '$lib/stores';
import { createModel, deleteModel } from '$lib/apis/ollama'; import { createModel, deleteModel } from '$lib/apis/ollama';
@ -14,6 +14,8 @@
} from '$lib/apis/modelfiles'; } from '$lib/apis/modelfiles';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
const i18n = getContext('i18n');
let localModelfiles = []; let localModelfiles = [];
let importFiles; let importFiles;
@ -23,7 +25,7 @@
success = await deleteModel(localStorage.token, tagName); success = await deleteModel(localStorage.token, tagName);
if (success) { if (success) {
toast.success(`Deleted ${tagName}`); toast.success($i18n.t(`Deleted {tagName}`, { tagName }));
} }
return success; return success;
@ -36,7 +38,7 @@
}; };
const shareModelfile = async (modelfile) => { const shareModelfile = async (modelfile) => {
toast.success('Redirecting you to OpenWebUI Community'); toast.success($i18n.t('Redirecting you to OpenWebUI Community'));
const url = 'https://openwebui.com'; const url = 'https://openwebui.com';
@ -78,7 +80,7 @@
<div class="min-h-screen max-h-[100dvh] w-full flex justify-center dark:text-white"> <div class="min-h-screen max-h-[100dvh] w-full flex justify-center dark:text-white">
<div class="flex flex-col justify-between w-full overflow-y-auto"> <div class="flex flex-col justify-between w-full overflow-y-auto">
<div class="max-w-2xl mx-auto w-full px-3 md:px-0 my-10"> <div class="max-w-2xl mx-auto w-full px-3 md:px-0 my-10">
<div class=" text-2xl font-semibold mb-3">My Modelfiles</div> <div class=" text-2xl font-semibold mb-3">{$i18n.t('My Modelfiles')}</div>
<a class=" flex space-x-4 cursor-pointer w-full mb-2 px-3 py-2" href="/modelfiles/create"> <a class=" flex space-x-4 cursor-pointer w-full mb-2 px-3 py-2" href="/modelfiles/create">
<div class=" self-center w-10"> <div class=" self-center w-10">
@ -101,8 +103,8 @@
</div> </div>
<div class=" self-center"> <div class=" self-center">
<div class=" font-bold">Create a modelfile</div> <div class=" font-bold">{$i18n.t('Create a modelfile')}</div>
<div class=" text-sm">Customize Ollama models for a specific purpose</div> <div class=" text-sm">{$i18n.t('Customize Ollama models for a specific purpose')}</div>
</div> </div>
</a> </a>
@ -266,7 +268,7 @@
document.getElementById('modelfiles-import-input')?.click(); document.getElementById('modelfiles-import-input')?.click();
}} }}
> >
<div class=" self-center mr-2 font-medium">Import Modelfiles</div> <div class=" self-center mr-2 font-medium">{$i18n.t('Import Modelfiles')}</div>
<div class=" self-center"> <div class=" self-center">
<svg <svg
@ -290,7 +292,7 @@
saveModelfiles($modelfiles); saveModelfiles($modelfiles);
}} }}
> >
<div class=" self-center mr-2 font-medium">Export Modelfiles</div> <div class=" self-center mr-2 font-medium">{$i18n.t('Export Modelfiles')}</div>
<div class=" self-center"> <div class=" self-center">
<svg <svg
@ -331,7 +333,7 @@
await modelfiles.set(await getModelfiles(localStorage.token)); await modelfiles.set(await getModelfiles(localStorage.token));
}} }}
> >
<div class=" self-center mr-2 font-medium">Sync All</div> <div class=" self-center mr-2 font-medium">{$i18n.t('Sync All')}</div>
<div class=" self-center"> <div class=" self-center">
<svg <svg
@ -382,7 +384,7 @@
</div> </div>
<div class=" my-16"> <div class=" my-16">
<div class=" text-2xl font-semibold mb-3">Made by OpenWebUI Community</div> <div class=" text-2xl font-semibold mb-3">{$i18n.t('Made by OpenWebUI Community')}</div>
<a <a
class=" flex space-x-4 cursor-pointer w-full mb-2 px-3 py-2" class=" flex space-x-4 cursor-pointer w-full mb-2 px-3 py-2"
@ -409,8 +411,8 @@
</div> </div>
<div class=" self-center"> <div class=" self-center">
<div class=" font-bold">Discover a modelfile</div> <div class=" font-bold">{$i18n.t('Discover a modelfile')}</div>
<div class=" text-sm">Discover, download, and explore model presets</div> <div class=" text-sm">{$i18n.t('Discover, download, and explore model presets')}</div>
</div> </div>
</a> </a>
</div> </div>

View file

@ -6,10 +6,12 @@
import AdvancedParams from '$lib/components/chat/Settings/Advanced/AdvancedParams.svelte'; import AdvancedParams from '$lib/components/chat/Settings/Advanced/AdvancedParams.svelte';
import { splitStream } from '$lib/utils'; import { splitStream } from '$lib/utils';
import { onMount, tick } from 'svelte'; import { onMount, tick, getContext } from 'svelte';
import { createModel } from '$lib/apis/ollama'; import { createModel } from '$lib/apis/ollama';
import { createNewModelfile, getModelfileByTagName, getModelfiles } from '$lib/apis/modelfiles'; import { createNewModelfile, getModelfileByTagName, getModelfiles } from '$lib/apis/modelfiles';
const i18n = getContext('i18n');
let loading = false; let loading = false;
let filesInputElement; let filesInputElement;
@ -349,7 +351,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
}} }}
/> />
<div class=" text-2xl font-semibold mb-6">My Modelfiles</div> <div class=" text-2xl font-semibold mb-6">{$i18n.t('My Modelfiles')}</div>
<button <button
class="flex space-x-1" class="flex space-x-1"
@ -371,7 +373,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
/> />
</svg> </svg>
</div> </div>
<div class=" self-center font-medium text-sm">Back</div> <div class=" self-center font-medium text-sm">{$i18n.t('Back')}</div>
</button> </button>
<hr class="my-3 dark:border-gray-700" /> <hr class="my-3 dark:border-gray-700" />
@ -418,7 +420,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
<div class="my-2 flex space-x-2"> <div class="my-2 flex space-x-2">
<div class="flex-1"> <div class="flex-1">
<div class=" text-sm font-semibold mb-2">Name*</div> <div class=" text-sm font-semibold mb-2">{$i18n.t('Name')}*</div>
<div> <div>
<input <input
@ -431,7 +433,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
</div> </div>
<div class="flex-1"> <div class="flex-1">
<div class=" text-sm font-semibold mb-2">Model Tag Name*</div> <div class=" text-sm font-semibold mb-2">{$i18n.t('Model Tag Name')}*</div>
<div> <div>
<input <input
@ -445,7 +447,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
</div> </div>
<div class="my-2"> <div class="my-2">
<div class=" text-sm font-semibold mb-2">Description*</div> <div class=" text-sm font-semibold mb-2">{$i18n.t('Description')}*</div>
<div> <div>
<input <input
@ -459,7 +461,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
<div class="my-2"> <div class="my-2">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-sm font-semibold">Modelfile</div> <div class=" self-center text-sm font-semibold">{$i18n.t('Modelfile')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -469,9 +471,9 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
}} }}
> >
{#if raw} {#if raw}
<span class="ml-2 self-center"> Raw Format </span> <span class="ml-2 self-center"> {$i18n.t('Raw Format')} </span>
{:else} {:else}
<span class="ml-2 self-center"> Builder Mode </span> <span class="ml-2 self-center"> {$i18n.t('Builder Mode')} </span>
{/if} {/if}
</button> </button>
</div> </div>
@ -480,7 +482,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
{#if raw} {#if raw}
<div class="mt-2"> <div class="mt-2">
<div class=" text-xs font-semibold mb-2">Content*</div> <div class=" text-xs font-semibold mb-2">{$i18n.t('Content')}*</div>
<div> <div>
<textarea <textarea
@ -493,12 +495,13 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
</div> </div>
<div class="text-xs text-gray-400 dark:text-gray-500"> <div class="text-xs text-gray-400 dark:text-gray-500">
Not sure what to write? Switch to <button {$i18n.t('Not sure what to write? Switch to')}
<button
class="text-gray-500 dark:text-gray-300 font-medium cursor-pointer" class="text-gray-500 dark:text-gray-300 font-medium cursor-pointer"
type="button" type="button"
on:click={() => { on:click={() => {
raw = !raw; raw = !raw;
}}>Builder Mode</button }}>{$i18n.t('Builder Mode')}</button
> >
or or
<a <a
@ -506,13 +509,13 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
href="https://openwebui.com" href="https://openwebui.com"
target="_blank" target="_blank"
> >
Click here to check other modelfiles. {$i18n.t('Click here to check other modelfiles.')}
</a> </a>
</div> </div>
</div> </div>
{:else} {:else}
<div class="my-2"> <div class="my-2">
<div class=" text-xs font-semibold mb-2">From (Base Model)*</div> <div class=" text-xs font-semibold mb-2">{$i18n.t('From (Base Model)')}*</div>
<div> <div>
<input <input
@ -524,16 +527,17 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
</div> </div>
<div class="mt-1 text-xs text-gray-400 dark:text-gray-500"> <div class="mt-1 text-xs text-gray-400 dark:text-gray-500">
To access the available model names for downloading, <a {$i18n.t('To access the available model names for downloading,')}
<a
class=" text-gray-500 dark:text-gray-300 font-medium" class=" text-gray-500 dark:text-gray-300 font-medium"
href="https://ollama.com/library" href="https://ollama.com/library"
target="_blank">click here.</a target="_blank">{$i18n.t('click here.')}</a
> >
</div> </div>
</div> </div>
<div class="my-1"> <div class="my-1">
<div class=" text-xs font-semibold mb-2">System Prompt</div> <div class=" text-xs font-semibold mb-2">{$i18n.t('System Prompt')}</div>
<div> <div>
<textarea <textarea
@ -546,7 +550,9 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
</div> </div>
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-sm font-semibold">Modelfile Advanced Settings</div> <div class=" self-center text-sm font-semibold">
{$i18n.t('Modelfile Advanced Settings')}
</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -556,16 +562,16 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
}} }}
> >
{#if advanced} {#if advanced}
<span class="ml-2 self-center"> Custom </span> <span class="ml-2 self-center">{$i18n.t(' Custom ')}</span>
{:else} {:else}
<span class="ml-2 self-center"> Default </span> <span class="ml-2 self-center">{$i18n.t(' Default ')}</span>
{/if} {/if}
</button> </button>
</div> </div>
{#if advanced} {#if advanced}
<div class="my-2"> <div class="my-2">
<div class=" text-xs font-semibold mb-2">Template</div> <div class=" text-xs font-semibold mb-2">{$i18n.t('Template')}</div>
<div> <div>
<textarea <textarea
@ -578,7 +584,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
</div> </div>
<div class="my-2"> <div class="my-2">
<div class=" text-xs font-semibold mb-2">Parameters</div> <div class=" text-xs font-semibold mb-2">{$i18n.t('Parameters')}</div>
<div> <div>
<AdvancedParams bind:options /> <AdvancedParams bind:options />
@ -590,7 +596,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
<div class="my-2"> <div class="my-2">
<div class="flex w-full justify-between mb-2"> <div class="flex w-full justify-between mb-2">
<div class=" self-center text-sm font-semibold">Prompt suggestions</div> <div class=" self-center text-sm font-semibold">{$i18n.t('Prompt suggestions')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -647,7 +653,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
</div> </div>
<div class="my-2"> <div class="my-2">
<div class=" text-sm font-semibold mb-2">Categories</div> <div class=" text-sm font-semibold mb-2">{$i18n.t('Categories')}</div>
<div class="grid grid-cols-4"> <div class="grid grid-cols-4">
{#each Object.keys(categories) as category} {#each Object.keys(categories) as category}
@ -661,7 +667,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
{#if pullProgress !== null} {#if pullProgress !== null}
<div class="my-2"> <div class="my-2">
<div class=" text-sm font-semibold mb-2">Pull Progress</div> <div class=" text-sm font-semibold mb-2">{$i18n.t('Pull Progress')}</div>
<div class="w-full rounded-full dark:bg-gray-800"> <div class="w-full rounded-full dark:bg-gray-800">
<div <div
class="dark:bg-gray-600 bg-gray-500 text-xs font-medium text-gray-100 text-center p-0.5 leading-none rounded-full" class="dark:bg-gray-600 bg-gray-500 text-xs font-medium text-gray-100 text-center p-0.5 leading-none rounded-full"
@ -684,7 +690,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
type="submit" type="submit"
disabled={loading} disabled={loading}
> >
<div class=" self-center font-medium">Save & Create</div> <div class=" self-center font-medium">{$i18n.t('Save & Create')}</div>
{#if loading} {#if loading}
<div class="ml-1.5 self-center"> <div class="ml-1.5 self-center">

View file

@ -3,7 +3,7 @@
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { onMount } from 'svelte'; import { onMount, getContext } from 'svelte';
import { page } from '$app/stores'; import { page } from '$app/stores';
import { settings, user, config, modelfiles } from '$lib/stores'; import { settings, user, config, modelfiles } from '$lib/stores';
@ -14,6 +14,8 @@
import AdvancedParams from '$lib/components/chat/Settings/Advanced/AdvancedParams.svelte'; import AdvancedParams from '$lib/components/chat/Settings/Advanced/AdvancedParams.svelte';
const i18n = getContext('i18n');
let loading = false; let loading = false;
let filesInputElement; let filesInputElement;
@ -248,7 +250,7 @@
}} }}
/> />
<div class=" text-2xl font-semibold mb-6">My Modelfiles</div> <div class=" text-2xl font-semibold mb-6">{$i18n.t('My Modelfiles')}</div>
<button <button
class="flex space-x-1" class="flex space-x-1"
@ -270,7 +272,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center font-medium text-sm">Back</div> <div class=" self-center font-medium text-sm">{$i18n.t('Back')}</div>
</button> </button>
<hr class="my-3 dark:border-gray-700" /> <hr class="my-3 dark:border-gray-700" />
@ -317,7 +319,7 @@
<div class="my-2 flex space-x-2"> <div class="my-2 flex space-x-2">
<div class="flex-1"> <div class="flex-1">
<div class=" text-sm font-semibold mb-2">Name*</div> <div class=" text-sm font-semibold mb-2">{$i18n.t('Name')}*</div>
<div> <div>
<input <input
@ -330,7 +332,7 @@
</div> </div>
<div class="flex-1"> <div class="flex-1">
<div class=" text-sm font-semibold mb-2">Model Tag Name*</div> <div class=" text-sm font-semibold mb-2">{$i18n.t('Model Tag Name')}*</div>
<div> <div>
<input <input
@ -345,7 +347,7 @@
</div> </div>
<div class="my-2"> <div class="my-2">
<div class=" text-sm font-semibold mb-2">Description*</div> <div class=" text-sm font-semibold mb-2">{$i18n.t('Description')}*</div>
<div> <div>
<input <input
@ -359,13 +361,13 @@
<div class="my-2"> <div class="my-2">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-sm font-semibold">Modelfile</div> <div class=" self-center text-sm font-semibold">{$i18n.t('Modelfile')}</div>
</div> </div>
<!-- <div class=" text-sm font-semibold mb-2"></div> --> <!-- <div class=" text-sm font-semibold mb-2"></div> -->
<div class="mt-2"> <div class="mt-2">
<div class=" text-xs font-semibold mb-2">Content*</div> <div class=" text-xs font-semibold mb-2">{$i18n.t('Content')}*</div>
<div> <div>
<textarea <textarea
@ -381,7 +383,7 @@
<div class="my-2"> <div class="my-2">
<div class="flex w-full justify-between mb-2"> <div class="flex w-full justify-between mb-2">
<div class=" self-center text-sm font-semibold">Prompt suggestions</div> <div class=" self-center text-sm font-semibold">{$i18n.t('Prompt suggestions')}</div>
<button <button
class="p-1 px-3 text-xs flex rounded transition" class="p-1 px-3 text-xs flex rounded transition"
@ -438,7 +440,7 @@
</div> </div>
<div class="my-2"> <div class="my-2">
<div class=" text-sm font-semibold mb-2">Categories</div> <div class=" text-sm font-semibold mb-2">{$i18n.t('Categories')}</div>
<div class="grid grid-cols-4"> <div class="grid grid-cols-4">
{#each Object.keys(categories) as category} {#each Object.keys(categories) as category}
@ -453,7 +455,7 @@
{#if pullProgress !== null} {#if pullProgress !== null}
<div class="my-2"> <div class="my-2">
<div class=" text-sm font-semibold mb-2">Pull Progress</div> <div class=" text-sm font-semibold mb-2">{$i18n.t('Pull Progress')}</div>
<div class="w-full rounded-full dark:bg-gray-800"> <div class="w-full rounded-full dark:bg-gray-800">
<div <div
class="dark:bg-gray-600 text-xs font-medium text-blue-100 text-center p-0.5 leading-none rounded-full" class="dark:bg-gray-600 text-xs font-medium text-blue-100 text-center p-0.5 leading-none rounded-full"
@ -476,7 +478,7 @@
type="submit" type="submit"
disabled={loading} disabled={loading}
> >
<div class=" self-center font-medium">Save & Update</div> <div class=" self-center font-medium">{$i18n.t('Save & Update')}</div>
{#if loading} {#if loading}
<div class="ml-1.5 self-center"> <div class="ml-1.5 self-center">

View file

@ -3,17 +3,19 @@
import fileSaver from 'file-saver'; import fileSaver from 'file-saver';
const { saveAs } = fileSaver; const { saveAs } = fileSaver;
import { onMount } from 'svelte'; import { onMount, getContext } from 'svelte';
import { WEBUI_NAME, prompts } from '$lib/stores'; import { WEBUI_NAME, prompts } from '$lib/stores';
import { createNewPrompt, deletePromptByCommand, getPrompts } from '$lib/apis/prompts'; import { createNewPrompt, deletePromptByCommand, getPrompts } from '$lib/apis/prompts';
import { error } from '@sveltejs/kit'; import { error } from '@sveltejs/kit';
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
const i18n = getContext('i18n');
let importFiles = ''; let importFiles = '';
let query = ''; let query = '';
const sharePrompt = async (prompt) => { const sharePrompt = async (prompt) => {
toast.success('Redirecting you to OpenWebUI Community'); toast.success($i18n.t('Redirecting you to OpenWebUI Community'));
const url = 'https://openwebui.com'; const url = 'https://openwebui.com';
@ -46,7 +48,7 @@
<div class="flex flex-col justify-between w-full overflow-y-auto"> <div class="flex flex-col justify-between w-full overflow-y-auto">
<div class="max-w-2xl mx-auto w-full px-3 md:px-0 my-10"> <div class="max-w-2xl mx-auto w-full px-3 md:px-0 my-10">
<div class="mb-6 flex justify-between items-center"> <div class="mb-6 flex justify-between items-center">
<div class=" text-2xl font-semibold self-center">My Prompts</div> <div class=" text-2xl font-semibold self-center">{$i18n.t('My Prompts')}</div>
</div> </div>
<div class=" flex w-full space-x-2"> <div class=" flex w-full space-x-2">
@ -245,7 +247,7 @@
document.getElementById('prompts-import-input')?.click(); document.getElementById('prompts-import-input')?.click();
}} }}
> >
<div class=" self-center mr-2 font-medium">Import Prompts</div> <div class=" self-center mr-2 font-medium">{$i18n.t('Import Prompts')}</div>
<div class=" self-center"> <div class=" self-center">
<svg <svg
@ -273,7 +275,7 @@
saveAs(blob, `prompts-export-${Date.now()}.json`); saveAs(blob, `prompts-export-${Date.now()}.json`);
}} }}
> >
<div class=" self-center mr-2 font-medium">Export Prompts</div> <div class=" self-center mr-2 font-medium">{$i18n.t('Export Prompts')}</div>
<div class=" self-center"> <div class=" self-center">
<svg <svg
@ -302,7 +304,7 @@
</div> </div>
<div class=" my-16"> <div class=" my-16">
<div class=" text-2xl font-semibold mb-3">Made by OpenWebUI Community</div> <div class=" text-2xl font-semibold mb-3">{$i18n.t('Made by OpenWebUI Community')}</div>
<a <a
class=" flex space-x-4 cursor-pointer w-full mb-3 px-3 py-2" class=" flex space-x-4 cursor-pointer w-full mb-3 px-3 py-2"
@ -329,8 +331,8 @@
</div> </div>
<div class=" self-center"> <div class=" self-center">
<div class=" font-bold">Discover a prompt</div> <div class=" font-bold">{$i18n.t('Discover a prompt')}</div>
<div class=" text-sm">Discover, download, and explore custom prompts</div> <div class=" text-sm">{$i18n.t('Discover, download, and explore custom prompts')}</div>
</div> </div>
</a> </a>
</div> </div>

View file

@ -3,10 +3,12 @@
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { prompts } from '$lib/stores'; import { prompts } from '$lib/stores';
import { onMount, tick } from 'svelte'; import { onMount, tick, getContext } from 'svelte';
import { createNewPrompt, getPrompts } from '$lib/apis/prompts'; import { createNewPrompt, getPrompts } from '$lib/apis/prompts';
const i18n = getContext('i18n');
let loading = false; let loading = false;
// /////////// // ///////////
@ -92,7 +94,7 @@
<div class="min-h-screen max-h-[100dvh] w-full flex justify-center dark:text-white"> <div class="min-h-screen max-h-[100dvh] w-full flex justify-center dark:text-white">
<div class=" flex flex-col justify-between w-full overflow-y-auto"> <div class=" flex flex-col justify-between w-full overflow-y-auto">
<div class="max-w-2xl mx-auto w-full px-3 md:px-0 my-10"> <div class="max-w-2xl mx-auto w-full px-3 md:px-0 my-10">
<div class=" text-2xl font-semibold mb-6">My Prompts</div> <div class=" text-2xl font-semibold mb-6">{$i18n.t('My Prompts')}</div>
<button <button
class="flex space-x-1" class="flex space-x-1"
@ -114,7 +116,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center font-medium text-sm">Back</div> <div class=" self-center font-medium text-sm">{$i18n.t('Back')}</div>
</button> </button>
<hr class="my-3 dark:border-gray-700" /> <hr class="my-3 dark:border-gray-700" />
@ -125,7 +127,7 @@
}} }}
> >
<div class="my-2"> <div class="my-2">
<div class=" text-sm font-semibold mb-2">Title*</div> <div class=" text-sm font-semibold mb-2">{$i18n.t('Title')}*</div>
<div> <div>
<input <input
@ -138,7 +140,7 @@
</div> </div>
<div class="my-2"> <div class="my-2">
<div class=" text-sm font-semibold mb-2">Command*</div> <div class=" text-sm font-semibold mb-2">{$i18n.t('Command')}*</div>
<div class="flex items-center mb-1"> <div class="flex items-center mb-1">
<div <div
@ -168,7 +170,7 @@
<div class="my-2"> <div class="my-2">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-sm font-semibold">Prompt Content*</div> <div class=" self-center text-sm font-semibold">{$i18n.t('Prompt Content')}*</div>
</div> </div>
<div class="mt-2"> <div class="mt-2">
@ -207,7 +209,7 @@
type="submit" type="submit"
disabled={loading} disabled={loading}
> >
<div class=" self-center font-medium">Save & Create</div> <div class=" self-center font-medium">{$i18n.t('Save & Create')}</div>
{#if loading} {#if loading}
<div class="ml-1.5 self-center"> <div class="ml-1.5 self-center">

View file

@ -3,7 +3,9 @@
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { prompts } from '$lib/stores'; import { prompts } from '$lib/stores';
import { onMount, tick } from 'svelte'; import { onMount, tick, getContext } from 'svelte';
const i18n = getContext('i18n');
import { getPrompts, updatePromptByCommand } from '$lib/apis/prompts'; import { getPrompts, updatePromptByCommand } from '$lib/apis/prompts';
import { page } from '$app/stores'; import { page } from '$app/stores';
@ -74,7 +76,7 @@
<div class="min-h-screen max-h-[100dvh] w-full flex justify-center dark:text-white"> <div class="min-h-screen max-h-[100dvh] w-full flex justify-center dark:text-white">
<div class="flex flex-col justify-between w-full overflow-y-auto"> <div class="flex flex-col justify-between w-full overflow-y-auto">
<div class="max-w-2xl mx-auto w-full px-3 md:px-0 my-10"> <div class="max-w-2xl mx-auto w-full px-3 md:px-0 my-10">
<div class=" text-2xl font-semibold mb-6">My Prompts</div> <div class=" text-2xl font-semibold mb-6">{$i18n.t('My Prompts')}</div>
<button <button
class="flex space-x-1" class="flex space-x-1"
@ -96,7 +98,7 @@
/> />
</svg> </svg>
</div> </div>
<div class=" self-center font-medium text-sm">Back</div> <div class=" self-center font-medium text-sm">{$i18n.t('Back')}</div>
</button> </button>
<hr class="my-3 dark:border-gray-700" /> <hr class="my-3 dark:border-gray-700" />
@ -107,7 +109,7 @@
}} }}
> >
<div class="my-2"> <div class="my-2">
<div class=" text-sm font-semibold mb-2">Title*</div> <div class=" text-sm font-semibold mb-2">{$i18n.t('Title')}*</div>
<div> <div>
<input <input
@ -120,7 +122,7 @@
</div> </div>
<div class="my-2"> <div class="my-2">
<div class=" text-sm font-semibold mb-2">Command*</div> <div class=" text-sm font-semibold mb-2">{$i18n.t('Command')}*</div>
<div class="flex items-center mb-1"> <div class="flex items-center mb-1">
<div <div
@ -151,7 +153,7 @@
<div class="my-2"> <div class="my-2">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<div class=" self-center text-sm font-semibold">Prompt Content*</div> <div class=" self-center text-sm font-semibold">{$i18n.t('Prompt Content')}*</div>
</div> </div>
<div class="mt-2"> <div class="mt-2">
@ -184,7 +186,7 @@
type="submit" type="submit"
disabled={loading} disabled={loading}
> >
<div class=" self-center font-medium">Save & Update</div> <div class=" self-center font-medium">{$i18n.t('Save & Update')}</div>
{#if loading} {#if loading}
<div class="ml-1.5 self-center"> <div class="ml-1.5 self-center">

View file

@ -3,9 +3,11 @@
import { userSignIn, userSignUp } from '$lib/apis/auths'; import { userSignIn, userSignUp } from '$lib/apis/auths';
import { WEBUI_API_BASE_URL, WEBUI_BASE_URL } from '$lib/constants'; import { WEBUI_API_BASE_URL, WEBUI_BASE_URL } from '$lib/constants';
import { WEBUI_NAME, config, user } from '$lib/stores'; import { WEBUI_NAME, config, user } from '$lib/stores';
import { onMount } from 'svelte'; import { onMount, getContext } from 'svelte';
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
const i18n = getContext('i18n');
let loaded = false; let loaded = false;
let mode = 'signin'; let mode = 'signin';
@ -16,7 +18,7 @@
const setSessionUser = async (sessionUser) => { const setSessionUser = async (sessionUser) => {
if (sessionUser) { if (sessionUser) {
console.log(sessionUser); console.log(sessionUser);
toast.success(`You're now logged in.`); toast.success($i18n.t(`You're now logged in.`));
localStorage.token = sessionUser.token; localStorage.token = sessionUser.token;
await user.set(sessionUser); await user.set(sessionUser);
goto('/'); goto('/');
@ -109,7 +111,7 @@
<div class="flex flex-col mt-4"> <div class="flex flex-col mt-4">
{#if mode === 'signup'} {#if mode === 'signup'}
<div> <div>
<div class=" text-sm font-semibold text-left mb-1">Name</div> <div class=" text-sm font-semibold text-left mb-1">{$i18n.t('Name')}</div>
<input <input
bind:value={name} bind:value={name}
type="text" type="text"
@ -124,7 +126,7 @@
{/if} {/if}
<div class="mb-2"> <div class="mb-2">
<div class=" text-sm font-semibold text-left mb-1">Email</div> <div class=" text-sm font-semibold text-left mb-1">{$i18n.t('Email')}</div>
<input <input
bind:value={email} bind:value={email}
type="email" type="email"
@ -136,7 +138,7 @@
</div> </div>
<div> <div>
<div class=" text-sm font-semibold text-left mb-1">Password</div> <div class=" text-sm font-semibold text-left mb-1">{$i18n.t('Password')}</div>
<input <input
bind:value={password} bind:value={password}
type="password" type="password"

View file

@ -1,7 +1,9 @@
<script> <script>
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { WEBUI_NAME, config } from '$lib/stores'; import { WEBUI_NAME, config } from '$lib/stores';
import { onMount } from 'svelte'; import { onMount, getContext } from 'svelte';
const i18n = getContext('i18n');
let loaded = false; let loaded = false;
@ -19,22 +21,25 @@
<div class="absolute rounded-xl w-full h-full backdrop-blur flex justify-center"> <div class="absolute rounded-xl w-full h-full backdrop-blur flex justify-center">
<div class="m-auto pb-44 flex flex-col justify-center"> <div class="m-auto pb-44 flex flex-col justify-center">
<div class="max-w-md"> <div class="max-w-md">
<div class="text-center text-2xl font-medium z-50">{$WEBUI_NAME} Backend Required</div> <div class="text-center text-2xl font-medium z-50">
{$i18n.t('{{webui_name}} Backend Required', { webui_name: $WEBUI_NAME })}
</div>
<div class=" mt-4 text-center text-sm w-full"> <div class=" mt-4 text-center text-sm w-full">
Oops! You're using an unsupported method (frontend only). Please serve the WebUI from {$i18n.t(
the backend. "Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend."
)}
<br class=" " /> <br class=" " />
<br class=" " /> <br class=" " />
<a <a
class=" font-semibold underline" class=" font-semibold underline"
href="https://github.com/open-webui/open-webui#how-to-install-" href="https://github.com/open-webui/open-webui#how-to-install-"
target="_blank">See readme.md for instructions</a target="_blank">{$i18n.t('See readme.md for instructions')}</a
> >
or {$i18n.t('or')}
<a class=" font-semibold underline" href="https://discord.gg/5rJgQTnV4s" target="_blank" <a class=" font-semibold underline" href="https://discord.gg/5rJgQTnV4s" target="_blank"
>join our Discord for help.</a >{$i18n.t('join our Discord for help.')}</a
> >
</div> </div>
@ -45,7 +50,7 @@
location.href = '/'; location.href = '/';
}} }}
> >
Check Again {$i18n.t('Check Again')}
</button> </button>
</div> </div>
</div> </div>