Unverified Commit db0712ae authored by Danny Liu's avatar Danny Liu Committed by GitHub
Browse files

Merge branch 'dev' into feat/system-wide-theme

parents f1716f45 e414b9ea
<script lang="ts">
export let className = 'w-4 h-4';
export let strokeWidth = '1.5';
</script>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width={strokeWidth}
stroke="currentColor"
class={className}
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125"
/>
</svg>
<script lang="ts">
import { getContext } from 'svelte';
import { toast } from 'svelte-sonner';
import fileSaver from 'file-saver';
const { saveAs } = fileSaver;
......@@ -9,6 +10,8 @@
import TagInput from '../common/Tags/TagInput.svelte';
import Tags from '../common/Tags.svelte';
const i18n = getContext('i18n');
export let initNewChat: Function;
export let title: string = $WEBUI_NAME;
export let shareEnabled: boolean = false;
......@@ -26,7 +29,7 @@
const chat = (await getChatById(localStorage.token, $chatId)).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 = 'http://localhost:5173';
......
This diff is collapsed.
<script lang="ts">
import { DropdownMenu } from 'bits-ui';
import Dropdown from '$lib/components/common/Dropdown.svelte';
import GarbageBin from '$lib/components/icons/GarbageBin.svelte';
import Pencil from '$lib/components/icons/Pencil.svelte';
import Tooltip from '$lib/components/common/Tooltip.svelte';
export let renameHandler: Function;
export let deleteHandler: Function;
export let onClose: Function;
</script>
<Dropdown
on:change={(e) => {
if (e.detail === false) {
onClose();
}
}}
>
<Tooltip content="More">
<slot />
</Tooltip>
<div slot="content">
<DropdownMenu.Content
class="w-full max-w-[130px] rounded-lg px-1 py-1.5 border border-gray-700/50 z-50 bg-gray-850 text-white"
sideOffset={8}
side="bottom"
align="start"
>
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer"
on:click={() => {
renameHandler();
}}
>
<Pencil strokeWidth="2" />
<div class="flex items-center">Rename</div>
</DropdownMenu.Item>
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer"
on:click={() => {
deleteHandler();
}}
>
<GarbageBin strokeWidth="2" />
<div class="flex items-center">Delete</div>
</DropdownMenu.Item>
</DropdownMenu.Content>
</div>
</Dropdown>
<script lang="ts">
import { onMount } from 'svelte';
import { onMount, getContext } from 'svelte';
const i18n = getContext('i18n');
export let messages = [];
let textAreaElement: HTMLTextAreaElement;
......@@ -19,16 +21,20 @@
class="px-2 py-1 text-sm font-semibold uppercase min-w-[6rem] text-left dark:group-hover:bg-gray-800 rounded-lg transition"
on:click={() => {
message.role = message.role === 'user' ? 'assistant' : 'user';
}}>{message.role}</button
}}>{$i18n.t(message.role)}</button
>
</div>
<div class="flex-1">
<!-- $i18n.t('a user') -->
<!-- $i18n.t('an assistant') -->
<textarea
id="{message.role}-{idx}-textarea"
bind:this={textAreaElement}
class="w-full bg-transparent outline-none rounded-lg p-2 text-sm resize-none overflow-hidden"
placeholder="Enter {message.role === 'user' ? 'a user' : 'an assistant'} message here"
placeholder={$i18n.t(`Enter {{role}} message here`, {
role: message.role === 'user' ? $i18n.t('a user') : $i18n.t('an assistant')
})}
rows="1"
on:input={(e) => {
textAreaElement.style.height = '';
......@@ -100,6 +106,6 @@
</svg>
</div>
<div class=" text-sm font-medium">Add message</div>
<div class=" text-sm font-medium">{$i18n.t('Add message')}</div>
</button>
</div>
import i18next from 'i18next';
import resourcesToBackend from 'i18next-resources-to-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
import type { i18n as i18nType } from 'i18next';
import { writable } from 'svelte/store';
const createI18nStore = (i18n: i18nType) => {
const i18nWritable = writable(i18n);
i18n.on('initialized', () => {
i18nWritable.set(i18n);
});
i18n.on('loaded', () => {
i18nWritable.set(i18n);
});
i18n.on('added', () => i18nWritable.set(i18n));
i18n.on('languageChanged', () => {
i18nWritable.set(i18n);
});
return i18nWritable;
};
const createIsLoadingStore = (i18n: i18nType) => {
const isLoading = writable(false);
// if loaded resources are empty || {}, set loading to true
i18n.on('loaded', (resources) => {
// console.log('loaded:', resources);
Object.keys(resources).length !== 0 && isLoading.set(false);
});
// if resources failed loading, set loading to true
i18n.on('failedLoading', () => {
isLoading.set(true);
});
return isLoading;
};
i18next
.use(
resourcesToBackend(
(language: string, namespace: string) => import(`./locales/${language}/${namespace}.json`)
)
)
.use(LanguageDetector)
.init({
debug: false,
detection: {
order: ['querystring', 'localStorage', 'navigator'],
caches: ['localStorage'],
lookupQuerystring: 'lang',
lookupLocalStorage: 'locale'
},
fallbackLng: {
default: ['en-US']
},
ns: 'translation',
returnEmptyString: false,
interpolation: {
escapeValue: false // not needed for svelte as it escapes by default
}
});
const i18n = createI18nStore(i18next);
const isLoadingStore = createIsLoadingStore(i18next);
export const getLanguages = async () => {
const languages = (await import(`./locales/languages.json`)).default;
return languages;
};
export default i18n;
export const isLoading = isLoadingStore;
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
[
{
"code": "en-US",
"title": "English (US)"
},
{
"code": "fa-IR",
"title": "فارسی (Farsi)"
},
{
"code": "de-DE",
"title": "Deutsch"
},
{
"code": "fr-FR",
"title": "French (France)"
},
{
"code": "uk-UA",
"title": "Ukrainian"
},
{
"code": "zh-TW",
"title": "Chinese (Traditional)"
},
{
"code": "zh-CN",
"title": "Chinese (Simplified)"
}
]
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<script lang="ts">
import { toast } from 'svelte-sonner';
import { onMount, tick, getContext } from 'svelte';
import { openDB, deleteDB } from 'idb';
import fileSaver from 'file-saver';
const { saveAs } = fileSaver;
import { onMount, tick } from 'svelte';
import { goto } from '$app/navigation';
import { getOllamaModels, getOllamaVersion } from '$lib/apis/ollama';
......@@ -36,6 +36,8 @@
import ChangelogModal from '$lib/components/ChangelogModal.svelte';
import Tooltip from '$lib/components/common/Tooltip.svelte';
const i18n = getContext('i18n');
let ollamaVersion = '';
let loaded = false;
let showShortcutsButtonElement: HTMLButtonElement;
......@@ -199,7 +201,7 @@
{#if loaded}
<div class=" hidden lg:flex fixed bottom-0 right-0 px-3 py-3 z-10">
<Tooltip content="help" placement="left">
<Tooltip content="Help" placement="left">
<button
id="show-shortcuts-button"
bind:this={showShortcutsButtonElement}
......@@ -240,7 +242,7 @@
location.href = '/';
}}
>
Check Again
{$i18n.t('Check Again')}
</button>
<button
......@@ -248,7 +250,7 @@
on:click={async () => {
localStorage.removeItem('token');
location.href = '/auth';
}}>Sign Out</button
}}>{$i18n.t('Sign Out')}</button
>
</div>
</div>
......@@ -267,12 +269,14 @@
</div>
<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
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 <span
class="font-semibold dark:text-white">Settings > Chats > Import Chats</span
>. This ensures that your valuable conversations are securely saved to your backend
database. Thank you!
{$i18n.t(
"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"
)}
<span class="font-semibold dark:text-white"
>{$i18n.t('Settings')} > {$i18n.t('Chats')} > {$i18n.t('Import Chats')}</span
>. {$i18n.t(
'This ensures that your valuable conversations are securely saved to your backend database. Thank you!'
)}
</div>
<div class=" mt-6 mx-auto relative group w-fit">
......@@ -298,7 +302,7 @@
class="text-xs text-center w-full mt-2 text-gray-400 underline"
on:click={async () => {
localDBChats = [];
}}>Close</button
}}>{$i18n.t('Close')}</button
>
</div>
</div>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment