Skip to content

Commit

Permalink
Merge pull request #20 from kinxiel/main
Browse files Browse the repository at this point in the history
Basic functionality implemented for the language switcher
  • Loading branch information
treo authored Jul 1, 2024
2 parents 2dbb564 + 1b1dc33 commit f12890a
Show file tree
Hide file tree
Showing 11 changed files with 4,720 additions and 34 deletions.
4,451 changes: 4,451 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"svelte-legos": "^0.1.9",
"svelte-markdown": "^0.2.3",
"svelte-preprocess": "^4.10.7",
"sveltekit-i18n": "^2.4.2",
"tailwindcss": "^3.3.2",
"tslib": "^2.5.3",
"typescript": "^5.1.3",
Expand Down
34 changes: 34 additions & 0 deletions src/lib/translations/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import i18n, { type Config } from 'sveltekit-i18n';
import { Locale } from './util';
import translations from './translations';

/** Setup up the initial configuration. Pass in en as the default locale. */
const config: Config = {
initLocale: Locale.en,
translations,
};

export const { t, l, locales, locale, loadTranslations } = new i18n(config);

/* Working with translations
*
* This project uses the sveltekit-i18n library to support different languages.
* To add a language, you can start by adding the translations for that language
* in the `translations.ts` file. This file contains a JavaScript object with the
* locale (language code) as the root property, and the translations as properties
* on the object. These translations can later be accessed accordingly.
*
* `src/translations/lang.json` acts as the menu of languages available. Once you've
* completed the necessary translations, you can add the language code here, which
* will make it selectable in the app settings menu.
*
* The fallback language is set to English (en) by default. Once the user selects
* a language, the language is saved to local storage and is then used as the default
* locale for subsequent sessions.
*
* Tips:
* - If you need to work wth raw HTML tags within the translations, you can use raw
* HTML as a string and then use Svelte's {@html} to parse the string into valid HTML.
* This can be really useful because translations don't usually have hyperlinks at the
* same position.
*/
4 changes: 4 additions & 0 deletions src/lib/translations/lang.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"en": "English",
"ja": "日本語"
}
140 changes: 140 additions & 0 deletions src/lib/translations/translations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import lang from './lang.json';

export default ({
en: {
lang,
menu: {
darkMode: "Dark Mode",
backends: "Backends",
backupRestore: "Backup/Restore"
},
main: {
introduction: "Technologic is a powerful, feature-rich AI Chatbot Client that is designed to work seamlessly with OpenAI's API or any compatible backend. With a user-friendly interface and the ability to organize, modify, and manage your conversations, Technologic brings you a next-level chatting experience with your AI assistant.",
featuresHeading: "Features",
features: [
{
title: "Secure Storage",
description: "Your conversations are stored locally on your computer using your browser's IndexedDB storage."
},
{
title: "Backend Compatibility",
description: "Works with any backend compatible with OpenAI's API."
},
{
title: "Bring Your Own API Key",
description: "Easily configure your OpenAI API key or any other compatible backend."
},
{
title: "Organize Conversations",
description: "Keep your conversations tidy by organizing them into folders."
},
{
title: "Message Modification",
description: "Edit and modify messages, both sent and received, as needed."
},
{
title: "Custom Personality",
description: "Support for 'System Messages' to give your chatbot a unique personality (if supported by the backend)."
},
{
title: "Fork Conversations",
description: "Easily branch off into different topics without losing the context of previous conversations."
},
{
title: "Elaborate",
description: "Use the 'Go on' feature to prompt the bot to expand on its last message."
},
{
title: "Merge Messages",
description: "Combine messages to avoid fragmentation or incomplete code blocks."
},
{
title: "View Raw Message",
description: "Access the raw text of any message with the flip of a switch."
}
],
xpressai: "Technologic was created by <a href='https://www.xpress.ai'>Xpress AI</a>, a company that specializes in developing AI solutions. With a focus on delivering cutting-edge technology that enhances the user experience, Xpress.ai's team of experts developed 'Technologic' to provide a unique and powerful chat client that enables users to have more dynamic and engaging conversations.",
backendConfigurationWarning: "You must set your OpenAI credentials in the <a href='/settings/backends/OpenAI'>Backend Settings</a> to be able to use that backend.",
startNewConversation: "Start new Conversation"
},
settings: {
backend: {
backends: "Backends",
useModel: "Use Model"
},
backup: {
backupRestore: "Backup/Restore",
downloadDatabase: "Download Database",
reloadDatabase: "Reload Database"
}
}
},
ja: {
lang,
menu: {
darkMode: "表示",
backends: "バックエンド",
backupRestore: "バックアップ・リストア"
},
main: {
introduction: "Technologic は、OpenAI の API または互換性のあるバックエンドとシームレスに動作できる機能が豊富な AI チャットボット クライアントです。直感的なUIと会話を整理、変更、管理する機能を備えた Technologic は、AI アシスタントとの次のレベルのチャット 体験を提供します。",
featuresHeading: "特徴",
features: [
{
title: "安全なデータストレージ",
description: "ブラウザのIndexedDBを使用しているため、自分のデータがずっとローカルに保存されています。"
},
{
title: "バックエンドの互換性",
description: "OpenAIのAPIに互換性があれば、使用可能です。"
},
{
title: "自分のAPIキーをそのまま使える",
description: "OpenAI APIキーまたはその他の互換性のあるバックエンドを簡単に設定できます。"
},
{
title: "チャットを整理する",
description: "チャットをフォルダ構造に整理することが可能です。"
},
{
title: "メッセージが変更可能",
description: "必要に応じて、送信メッセージと受信メッセージの両方を編集および変更可能です。"
},
{
title: "チャットの雰囲気をカスタマイズできる",
description: "チャットボットに独自の個性を与える「システムメッセージ」の対応(バックエンドが対応されている場合のみ)"
},
{
title: "チャットをフォークする",
description: "以前のチャットのコンテキストを失うことなく、別のテーマに簡単に分岐することができます。"
},
{
title: "更に詳しく説明する",
description: "「Go on」機能を使用して、チャットの最後のプロンプトを更に詳しく説明させることができます。"
},
{
title: "チャットを結合させる",
description: "チャットを結合させることにより、メッセージおよびコードの断片化を避けることができます。"
},
{
title: "メッセージの生データを確認できる",
description: "メッセージの生データをいつでも確認することができます。"
}
],
xpressai: "Technologic は、AI ソリューションの開発を専門とする会社<a href='https://www.xpress.ai'>Xpress AI</a>が作成されました。 Xpress.ai の専門家チームは、ユーザー エクスペリエンスを向上させる最先端のテクノロジーの提供に重点を置いて、ユーザーがよりダイナミックで魅力的なチャットを可能にするユニークで強力なチャット クライアントを提供する「Technologic」を開発しました。",
backendConfigurationWarning: "バックエンドを使用できるようにするには、<a href='/settings/backends/OpenAI'>バックエンド設定</a>でOpenAI関連情報を設定する必要があります。",
startNewConversation: "新しいチャットを開始"
},
settings: {
backend: {
backends: "バックエンド",
useModel: "モデル"
},
backup: {
backupRestore: "バックアップ・リストア",
downloadDatabase: "データベースをダウンロード",
reloadDatabase: "データベースをリストア"
}
}
}
});
29 changes: 29 additions & 0 deletions src/lib/translations/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
enum Locale {
en = "en",
jp = "ja"
}

/** Gets the language locale from local storage given a key. If no locale is found,
* it resolves to use a default, which is passed in as the second parameter.*/
function getLocaleFromLocalStorageWithDefault(key: string = "locale", defaultLocale: Locale = Locale.en): string {
let locale = localStorage.getItem(key);

if (locale) {
return locale
} else {
return JSON.stringify(defaultLocale);
}

}

/** Gets the users default locale via browser's navigator property */
function getUserLocale(): string {
if (navigator.languages != undefined)
return navigator.languages[0];
return navigator.language;
}

export {
Locale,
getLocaleFromLocalStorageWithDefault
}
28 changes: 22 additions & 6 deletions src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import IconChevronLeft from '@tabler/icons-svelte/dist/svelte/icons/IconChevronLeft.svelte';
import IconChevronRight from '@tabler/icons-svelte/dist/svelte/icons/IconChevronRight.svelte';
import '../app.postcss';
import hljs from 'highlight.js/lib/core';
Expand All @@ -37,6 +36,16 @@
storePopup.set({ computePosition, autoUpdate, flip, shift, offset, arrow });
let hideSidebar = false;
// i18n support
import { t, locales, locale } from "$lib/translations";
import { getLocaleFromLocalStorageWithDefault, Locale } from '$lib/translations/util';
getLocaleFromLocalStorageWithDefault('locale', Locale.en);
function setLocalStorageLocale(event: any) {
const locale = event.target.value;
localStorage.setItem('locale', JSON.stringify(locale));
}
</script>

<Modal />
Expand All @@ -63,7 +72,7 @@
</a>
<div class="flex-grow mt-2">
<ul>
<li><a href="/new">Start new Conversation</a></li>
<li><a href="/new">{$t('main.startNewConversation')}</a></li>
<li><hr /></li>
<li><Folder folder={$folderStore} /></li>
</ul>
Expand All @@ -76,17 +85,24 @@
<div class="card">
<ul class="list">
<li class="flex p-2">
<LightSwitch /> <div>Dark Mode</div>
<LightSwitch /> <div>{$t('menu.darkMode')}</div>
</li>
</ul>
<nav class="list-nav">
<ul class="list-nav card p-2">
<li>
<a href="/settings/backends">Backends</a>
<a href="/settings/backends">{$t('menu.backends')}</a>
</li>
<li>
<a href="/settings/backup">Backup / Restore</a>
</li>
<a href="/settings/backup">{$t('menu.backupRestore')}</a>
</li>
<li>
<select class="ml-4 dark:text-black" on:change={setLocalStorageLocale} bind:value={$locale}>
{#each $locales as value}
<option {value}>{$t(`lang.${value}`)}</option>
{/each}
</select>
</li>
</ul>
</nav>
</div>
Expand Down
11 changes: 11 additions & 0 deletions src/routes/+layout.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
export const ssr = false;

// i18n
import { loadTranslations } from '$lib/translations';
import { Locale, getLocaleFromLocalStorageWithDefault } from '$lib/translations/util';

export const load = async ({ url }: any) => {
const { pathname } = url;
const initLocale = JSON.parse(getLocaleFromLocalStorageWithDefault("locale", Locale.en));

await loadTranslations(initLocale, pathname);
return {};
}
38 changes: 15 additions & 23 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<script lang="ts">
import IconMessageChatbot from '@tabler/icons-svelte/dist/svelte/icons/IconMessageChatbot.svelte';
import { configStore } from '$lib/stores/technologicStores';
import { t, l, locales } from '$lib/translations';
import { getLocaleFromLocalStorageWithDefault, Locale } from '$lib/translations/util';
getLocaleFromLocalStorageWithDefault('locale', Locale.en);
$: misconfiguredOpenAI = !$configStore.backends
.find((it) => it.name === 'OpenAI')
Expand All @@ -14,43 +17,32 @@
</header>
<section class="p-4 gap-4 flex flex-col">
<p>
Technologic is a powerful, feature-rich AI Chatbot Client that is designed to work seamlessly with OpenAI's API or any
compatible backend. With a user-friendly interface and the ability to organize, modify, and manage your conversations,
Technologic brings you a next-level chatting experience with your AI assistant.
{$t('main.introduction')}
</p>

<div>
<h3>Features</h3>
<h3>{$t('main.featuresHeading')}</h3>
<ul>
<li><strong>Secure Storage</strong>: Your conversations are stored locally on your computer using your browser's IndexedDB storage.</li>
<li><strong>Backend Compatibility</strong>: Works with any backend compatible with OpenAI's API.</li>
<li><strong>Bring Your Own API Key</strong>: Easily configure your OpenAI API key or any other compatible backend.</li>
<li><strong>Organize Conversations</strong>: Keep your conversations tidy by organizing them into folders.</li>
<li><strong>Message Modification</strong>: Edit and modify messages, both sent and received, as needed.</li>
<li><strong>Custom Personality</strong>: Support for "System Messages" to give your chatbot a unique personality (if supported by the backend).</li>
<li><strong>Fork Conversations</strong>: Easily branch off into different topics without losing the context of previous conversations.</li>
<li><strong>Elaborate</strong>: Use the "Go on" feature to prompt the bot to expand on its last message.</li>
<li><strong>Merge Messages</strong>: Combine messages to avoid fragmentation or incomplete code blocks.</li>
<li><strong>View Raw Message</strong>: Access the raw text of any message with the flip of a switch.</li>
{#each { length: 10 } as _, i}
<li>
<strong> {$t(`main.features.${i}.title`)}</strong>: {$t(
`main.features.${i}.description`
)}
</li>{/each}
</ul>
</div>

<div>
<h3>Made by Xpress AI</h3>
<p>
Technologic was created by <a href="https://www.xpress.ai">Xpress AI</a>, a company that
specializes in developing AI solutions. With a focus on delivering cutting-edge technology
that enhances the user experience, Xpress.ai's team of experts developed "Technologic" to
provide a unique and powerful chat client that enables users to have more dynamic and engaging
conversations.
</p>
<p>
{@html $t('main.xpressai')}
</p>
</div>
</section>
</main>

{#if misconfiguredOpenAI}
<section class="card variant-glass-error m-5 p-4">
You must set your OpenAI in the <a href="/settings/backends/OpenAI">Backend Settings</a> to be able
to use that backend.
{@html $t('main.backendConfigurationWarning')}
</section>
{/if}
8 changes: 6 additions & 2 deletions src/routes/settings/backends/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
import { configStore } from '$lib/stores/technologicStores';
import type { BackendConfiguration } from '$lib/stores/schema';
import { t, l, locales } from '$lib/translations';
import { getLocaleFromLocalStorageWithDefault, Locale } from '$lib/translations/util';
getLocaleFromLocalStorageWithDefault('locale', Locale.en);
$: currentBackend = $configStore.backends.find(
(backend) => backend.name === $configStore.backend.name
);
Expand All @@ -31,7 +35,7 @@
</script>

<section class="card p-3 m-3 variant-glass flex flex-col gap-2">
<h3>Backends</h3>
<h3>{$t('settings.backend.backends')}</h3>
<nav class="list-nav">
<ul>
{#each $configStore.backends as backend}
Expand All @@ -56,7 +60,7 @@
</section>

<section class="card p-3 m-3 variant-glass flex flex-col gap-2">
<h3>Use Model:</h3>
<h3>{$t('settings.backend.useModel')}:</h3>
<nav class="list-nav">
<ul>
{#each currentBackend.models as model}
Expand Down
Loading

0 comments on commit f12890a

Please sign in to comment.