···
1
1
<script>
2
2
import { Badge } from "$lib/components/ui/badge";
3
3
import X from "lucide-svelte/icons/x";
4
4
-
import { translateLanguages } from '$lib/stores/translateLanguages.svelte.js';
4
4
+
import { translateLanguages } from '$jibs/deprecrated/translateLanguages.svelte.js';
5
5
6
6
let selectedCodes = $derived(() => Object.keys(translateLanguages.languages));
7
7
-
7
7
+
8
8
function removeLanguage(code) {
9
9
-
// The store will handle normalization internally
10
9
translateLanguages.removeLanguage(code);
11
10
}
12
11
···
14
13
function handle_variant(hovered_lang) {
15
14
return hovered_lang == selected_lang_to_remove ? "destructive" : "outline";
16
15
}
17
17
-
18
16
</script>
19
17
20
18
<div class="selected-languages">
21
19
<ul>
22
22
-
{#each selectedCodes as langCode}
20
20
+
{#each selectedCodes as langCode (langCode)}
23
21
<li>
24
22
<Badge variant={handle_variant(langCode)}>
25
23
{translateLanguages.getLanguageInfo(langCode)?.label || langCode}
···
1
1
-
<script lang="ts">
2
2
-
import Check from "lucide-svelte/icons/check";
3
3
-
import { Combobox } from "bits-ui";
4
4
-
import { languages } from 'countries-list';
5
5
-
import LanguageList from './LanguageList.svelte';
6
6
-
import { translateLanguages } from '$lib/stores/translateLanguages.svelte.js';
7
7
-
import languageData from '$lib/data/wikidata-languages.json';
8
8
-
import { Languages, Plus } from 'lucide-svelte';
9
9
-
10
10
-
let selectedCodes = $derived(() => Object.keys(translateLanguages.languages));
11
11
-
12
12
-
const iso3ToIso1Map = new Map(
13
13
-
languageData.filter(lang => lang.iso1).map(lang => [lang.iso, lang.iso1])
14
14
-
);
15
15
-
16
16
-
const countryLanguages = new Map(
17
17
-
Object.entries(languages).map(([code, info]) => [code, {
18
18
-
value: code,
19
19
-
label: info.name,
20
20
-
native: info.native
21
21
-
}])
22
22
-
);
23
23
-
24
24
-
const customLanguages = new Map([
25
25
-
['scn', { value: 'scn', label: 'Sicilian', native: 'Sicilianu' }]
26
26
-
]);
27
27
-
28
28
-
const allLanguages = new Map();
29
29
-
countryLanguages.forEach((info, code) => allLanguages.set(code, info));
30
30
-
customLanguages.forEach((info, code) => allLanguages.set(code, info));
31
31
-
languageData.forEach(lang => {
32
32
-
if (!lang.iso1 && !allLanguages.has(lang.iso)) {
33
33
-
allLanguages.set(lang.iso, {
34
34
-
value: lang.iso,
35
35
-
label: lang.langLabel,
36
36
-
native: lang.nativeNames?.[0] || lang.langLabel
37
37
-
});
38
38
-
}
39
39
-
});
40
40
-
41
41
-
let inputValue = $state("");
42
42
-
let langs = $derived(() => Array.from(allLanguages.values()));
43
43
-
let filteredLangs = $derived(() => filterLanguages(inputValue));
44
44
-
45
45
-
function isLanguageSelected(langCode) {
46
46
-
const codeToCheck = iso3ToIso1Map.get(langCode) || langCode;
47
47
-
return selectedCodes.includes(codeToCheck) || selectedCodes.includes(langCode);
48
48
-
}
49
49
-
50
50
-
function handleLanguageAdd(langCode) {
51
51
-
const codeToUse = iso3ToIso1Map.get(langCode) || langCode;
52
52
-
const langInfo = allLanguages.get(codeToUse) || allLanguages.get(langCode);
53
53
-
if (!selectedCodes.includes(codeToUse)) {
54
54
-
translateLanguages.addLanguage(codeToUse, {
55
55
-
label: langInfo?.label || codeToUse,
56
56
-
native: langInfo?.native || codeToUse,
57
57
-
rtl: false,
58
58
-
display: true
59
59
-
});
60
60
-
}
61
61
-
inputValue = "";
62
62
-
}
63
63
-
64
64
-
function filterLanguages(inputValue) {
65
65
-
const lowerInput = inputValue.toLowerCase();
66
66
-
return langs
67
67
-
.filter(
68
68
-
(lang) =>
69
69
-
lang.value.toLowerCase().includes(lowerInput) ||
70
70
-
lang.label.toLowerCase().includes(lowerInput) ||
71
71
-
lang.native.toLowerCase().includes(lowerInput)
72
72
-
)
73
73
-
.sort((a, b) => {
74
74
-
const aExactMatch = a.value.toLowerCase() === lowerInput;
75
75
-
const bExactMatch = b.value.toLowerCase() === lowerInput;
76
76
-
if (aExactMatch && !bExactMatch) return -1;
77
77
-
if (!aExactMatch && bExactMatch) return 1;
78
78
-
const aStartsWith = a.value.toLowerCase().startsWith(lowerInput) ||
79
79
-
a.label.toLowerCase().startsWith(lowerInput) ||
80
80
-
a.native.toLowerCase().startsWith(lowerInput);
81
81
-
const bStartsWith = b.value.toLowerCase().startsWith(lowerInput) ||
82
82
-
b.label.toLowerCase().startsWith(lowerInput) ||
83
83
-
b.native.toLowerCase().startsWith(lowerInput);
84
84
-
if (aStartsWith && !bStartsWith) return -1;
85
85
-
if (!aStartsWith && bStartsWith) return 1;
86
86
-
return 0;
87
87
-
});
88
88
-
}
89
89
-
90
90
-
function handleKeyDown(event) {
91
91
-
if (event.key === 'Enter') {
92
92
-
const exactMatch = filteredLangs.find(lang => lang.value.toLowerCase() === inputValue.toLowerCase());
93
93
-
if (exactMatch) {
94
94
-
handleLanguageAdd(exactMatch.value);
95
95
-
}
96
96
-
}
97
97
-
}
98
98
-
99
99
-
function getLanguageName(lang) {
100
100
-
return lang.label || lang.native || lang.code;
101
101
-
}
102
102
-
</script>
103
103
-
104
104
-
<div class="flex gap-2 items-center">
105
105
-
<div class="flex gap-1">
106
106
-
{#each $translateLanguages as lang}
107
107
-
<button on:click={() => translateLanguages.removeLanguage(lang)} class="px-2 py-1 bg-gray-100 rounded hover:bg-gray-200">
108
108
-
{getLanguageName(lang)}
109
109
-
</button>
110
110
-
{/each}
111
111
-
</div>
112
112
-
<a href="/languages" class="p-2 hover:text-yellow-500 transition-colors" title="Add or remove languages">
113
113
-
<Languages class="w-5 h-5" />
114
114
-
</a>
115
115
-
</div>
116
116
-
117
117
-
<Combobox.Root items={filteredLangs} bind:inputValue touchedInput=open>
118
118
-
<div class="relative">
119
119
-
<Combobox.Input
120
120
-
class="inline-flex h-input w-[296px] truncate rounded-9px border border-border-input bg-background px-11 text-sm transition-colors placeholder:text-foreground-alt/50 focus:outline-none focus:ring-2 focus:ring-foreground focus:ring-offset-2 focus:ring-offset-background"
121
121
-
placeholder="Add a language" aria-label="Add a language" onkeydown={handleKeyDown} />
122
122
-
</div>
123
123
-
<Combobox.Content class="w-full rounded-xl border border-muted bg-background px-1 py-3 shadow-popover outline-none">
124
124
-
{#each filteredLangs as lang}
125
125
-
<Combobox.Item value={lang.value} label="{lang.label} | {lang.native}"
126
126
-
class="cursor-pointer flex items-center justify-between" onclick={()=> handleLanguageAdd(lang.value)}
127
127
-
>
128
128
-
<span class="flex items-center">
129
129
-
{#if isLanguageSelected(lang.value)}
130
130
-
<Check class="mr-2" />
131
131
-
{:else}
132
132
-
<span class="mr-2" style="width: 1em; height: 1em;"></span>
133
133
-
{/if}
134
134
-
{lang.label} | {lang.native}
135
135
-
</span>
136
136
-
</Combobox.Item>
137
137
-
{:else}
138
138
-
<span class="block px-5 py-2 text-sm text-muted-foreground">
139
139
-
No results found
140
140
-
</span>
141
141
-
{/each}
142
142
-
</Combobox.Content>
143
143
-
</Combobox.Root>
144
144
-
145
145
-
<LanguageList />
146
146
-
147
147
-
<style>
148
148
-
.language-picker {
149
149
-
display: grid;
150
150
-
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
151
151
-
gap: 10px;
152
152
-
max-height: 300px;
153
153
-
overflow-y: auto;
154
154
-
}
155
155
-
156
156
-
.language-item {
157
157
-
display: flex;
158
158
-
align-items: center;
159
159
-
gap: 8px;
160
160
-
}
161
161
-
162
162
-
.flag {
163
163
-
font-size: 1.5em;
164
164
-
}
165
165
-
166
166
-
.lang-name {
167
167
-
font-size: 0.9em;
168
168
-
}
169
169
-
170
170
-
.selected-languages {
171
171
-
margin-bottom: 20px;
172
172
-
}
173
173
-
174
174
-
.highlight {
175
175
-
color: blue;
176
176
-
}
177
177
-
</style>
···
10
10
DropdownMenuRadioItem,
11
11
DropdownMenuCheckboxItem
12
12
} from '$lib/components/ui/dropdown-menu';
13
13
-
import { translateLanguages } from '$lib/stores/translateLanguages.svelte.js';
13
13
+
import { translateLanguages } from '$jibs/deprecrated/translateLanguages.svelte.js';
14
14
15
15
import DropdownMenuLabel from '@/components/ui/dropdown-menu/dropdown-menu-label.svelte';
16
16
import { DropdownMenu, DropdownMenu } from 'bits-ui';
···
1
1
<script>
2
2
import { exampleTranslations } from '$lib/example';
3
3
-
import { translateLanguages } from '$lib/stores/translateLanguages.svelte.js';
4
3
import { translationHistory } from '$lib/stores/translationHistory.svelte.js';
5
4
import { exampleTyper } from '$lib/stores/exampleTyper.svelte.js';
6
5
import { translationStateMachine, STATES } from '$lib/stores/translationStateMachine.svelte.js';
···
13
12
import PlayPauseButton from './PlayPauseButton.svelte';
14
13
import { getColorByIndex } from '$lib/colors';
15
14
import { onMount, onDestroy } from 'svelte';
15
15
+
import { userStore } from '$lib/stores/user.svelte.js';
16
16
17
17
// State tracking variables
18
18
let isTyping = $state(false);
···
86
86
let truncate_lines = $state(true);
87
87
88
88
// Language management
89
89
-
let user_langs = $derived(translateLanguages.languages);
90
90
-
let tgt_langs = $derived(Object.keys(user_langs));
91
91
-
let show_langs = $derived(
89
89
+
let user_langs = $derived(() => userStore.user.selectedLanguages);
90
90
+
let tgt_langs = $derived(() => userStore.user.selectedLanguages);
91
91
+
let show_langs = $derived(() =>
92
92
Object.entries(user_langs)
93
93
.filter(([_, lang]) => lang.display)
94
94
.map(([key, _]) => key)
···
247
247
translationStateMachine.actions.userTyping();
248
248
exampleTyper.markUserTyped();
249
249
}
250
250
+
}
251
251
+
252
252
+
function addDefaultLanguages() {
253
253
+
// Set some default ISO codes (e.g. English, Russian, Japanese, Spanish, Italian, Catalan)
254
254
+
const defaults = ['eng', 'rus', 'jpn', 'spa', 'ita', 'cat'];
255
255
+
defaults.forEach(code => userStore.addLanguage(code));
256
256
+
toast.success("Added default languages");
250
257
}
251
258
</script>
252
259
···
1
1
+
<script lang="ts">
2
2
+
import { userStore } from '$lib/stores/user.svelte.js';
3
3
+
import languageData from '$lib/data/wikidata-languages.json';
4
4
+
import Check from "lucide-svelte/icons/check";
5
5
+
6
6
+
// All available languages
7
7
+
const allLanguages = languageData.map(lang => ({
8
8
+
code: lang.iso,
9
9
+
label: lang.langLabel,
10
10
+
native: lang.nativeNames?.[0] || lang.langLabel
11
11
+
}));
12
12
+
13
13
+
function addLanguage(code) {
14
14
+
userStore.addLanguage(code);
15
15
+
}
16
16
+
17
17
+
function removeLanguage(code) {
18
18
+
userStore.removeLanguage(code);
19
19
+
}
20
20
+
21
21
+
function isSelected(code) {
22
22
+
// Always reference the store directly for reactivity
23
23
+
return userStore.user.selectedLanguages.includes(code);
24
24
+
}
25
25
+
</script>
26
26
+
27
27
+
<!-- Selected languages at the top -->
28
28
+
<div class="selected-languages flex gap-2 mb-4 flex-wrap">
29
29
+
{#each userStore.user.selectedLanguages as code (code)}
30
30
+
<span class="px-2 py-1 bg-gray-200 rounded flex items-center gap-1">
31
31
+
{allLanguages.find(l => l.code === code)?.label || code}
32
32
+
<button on:click={() => removeLanguage(code)} aria-label="Remove">
33
33
+
×
34
34
+
</button>
35
35
+
</span>
36
36
+
{/each}
37
37
+
</div>
38
38
+
39
39
+
<!-- All languages (no sorting) -->
40
40
+
<ul class="all-languages space-y-1">
41
41
+
{#each allLanguages as lang (lang.code)}
42
42
+
<li class="flex items-center gap-2">
43
43
+
<button
44
44
+
disabled={isSelected(lang.code)}
45
45
+
on:click={() => addLanguage(lang.code)}
46
46
+
class="border rounded px-2 py-1"
47
47
+
aria-label={isSelected(lang.code) ? "Selected" : "Add"}
48
48
+
>
49
49
+
{#if isSelected(lang.code)}
50
50
+
<Check class="inline w-4 h-4 text-green-600" />
51
51
+
{:else}
52
52
+
+
53
53
+
{/if}
54
54
+
</button>
55
55
+
<span>{lang.label} <span class="text-gray-500">({lang.native})</span></span>
56
56
+
</li>
57
57
+
{/each}
58
58
+
</ul>
59
59
+
60
60
+
<style>
61
61
+
.selected-languages {
62
62
+
flex-wrap: wrap;
63
63
+
}
64
64
+
</style>
···
1
1
+
import { defaultLanguages } from '$lib/utils/languages.js';
2
2
+
import languageData from '$lib/data/wikidata-languages.json';
3
3
+
4
4
+
function normalizeLanguageCode(code) {
5
5
+
return code;
6
6
+
}
7
7
+
8
8
+
// Single source of truth for selected languages
9
9
+
let languages = $state({});
10
10
+
11
11
+
function loadFromStorage() {
12
12
+
if (typeof localStorage === 'undefined') return false;
13
13
+
try {
14
14
+
const saved = localStorage.getItem('user_langs');
15
15
+
if (saved) {
16
16
+
const parsed = JSON.parse(saved);
17
17
+
Object.keys(languages).forEach(k => delete languages[k]);
18
18
+
Object.assign(languages, parsed);
19
19
+
return true;
20
20
+
}
21
21
+
} catch (e) {
22
22
+
// ignore
23
23
+
}
24
24
+
return false;
25
25
+
}
26
26
+
27
27
+
function saveToStorage() {
28
28
+
if (typeof localStorage === 'undefined') return;
29
29
+
try {
30
30
+
localStorage.setItem('user_langs', JSON.stringify(languages));
31
31
+
localStorage.setItem('tgt_langs', JSON.stringify(Object.keys(languages)));
32
32
+
} catch (e) {
33
33
+
// ignore
34
34
+
}
35
35
+
}
36
36
+
37
37
+
function addLanguage(code, info) {
38
38
+
const normalized = normalizeLanguageCode(code);
39
39
+
if (!languages[normalized]) {
40
40
+
languages[normalized] = {
41
41
+
label: info.label || code,
42
42
+
native: info.native || code,
43
43
+
rtl: info.rtl || false,
44
44
+
display: true
45
45
+
};
46
46
+
saveToStorage();
47
47
+
}
48
48
+
}
49
49
+
50
50
+
function removeLanguage(code) {
51
51
+
const normalized = normalizeLanguageCode(code);
52
52
+
if (languages[normalized]) {
53
53
+
delete languages[normalized];
54
54
+
saveToStorage();
55
55
+
}
56
56
+
}
57
57
+
58
58
+
function clearLanguages() {
59
59
+
Object.keys(languages).forEach(k => delete languages[k]);
60
60
+
saveToStorage();
61
61
+
}
62
62
+
63
63
+
function resetToDefaults() {
64
64
+
Object.keys(languages).forEach(k => delete languages[k]);
65
65
+
Object.assign(languages, defaultLanguages);
66
66
+
saveToStorage();
67
67
+
}
68
68
+
69
69
+
function addDefaultLanguages() {
70
70
+
Object.assign(languages, defaultLanguages);
71
71
+
saveToStorage();
72
72
+
}
73
73
+
74
74
+
function toggleLanguageDisplay(code) {
75
75
+
const normalized = normalizeLanguageCode(code);
76
76
+
if (languages[normalized]) {
77
77
+
languages[normalized].display = !languages[normalized].display;
78
78
+
saveToStorage();
79
79
+
}
80
80
+
}
81
81
+
82
82
+
function getLanguageInfo(code) {
83
83
+
const normalized = normalizeLanguageCode(code);
84
84
+
return languages[normalized];
85
85
+
}
86
86
+
87
87
+
// On module load, initialize from storage or defaults
88
88
+
if (!loadFromStorage()) {
89
89
+
Object.assign(languages, defaultLanguages);
90
90
+
saveToStorage();
91
91
+
}
92
92
+
93
93
+
export const translateLanguages = {
94
94
+
languages, // $state object
95
95
+
addLanguage,
96
96
+
removeLanguage,
97
97
+
clearLanguages,
98
98
+
resetToDefaults,
99
99
+
addDefaultLanguages,
100
100
+
toggleLanguageDisplay,
101
101
+
getLanguageInfo,
102
102
+
normalizeLanguageCode
103
103
+
};
···
3
3
import { Settings } from "lucide-svelte";
4
4
import { toast } from "svelte-sonner";
5
5
import * as DropdownMenu from "$lib/components/ui/dropdown-menu";
6
6
-
import { translateLanguages } from '$lib/stores/translateLanguages.svelte.js'
7
6
import { userStore } from '$lib/stores/user.svelte.js';
8
7
import { defaultLanguages } from '$lib/utils/languages.js';
9
8
···
1
1
-
import { writable } from 'svelte/store';
2
2
-
import { translateLanguages } from './stores/translateLanguages.svelte.js';
3
3
-
4
4
-
// Create a writable store that syncs with translateLanguages
5
5
-
function createLanguagesStore() {
6
6
-
const { subscribe, set, update } = writable<string[]>([]);
7
7
-
8
8
-
return {
9
9
-
subscribe,
10
10
-
update: (fn: (value: string[]) => string[]) => {
11
11
-
update(fn);
12
12
-
// Sync with translateLanguages store
13
13
-
const newValue = fn([]);
14
14
-
newValue.forEach(code => {
15
15
-
if (!translateLanguages.languages[code]) {
16
16
-
translateLanguages.addLanguage(code, {
17
17
-
label: code,
18
18
-
native: code,
19
19
-
rtl: false,
20
20
-
display: true
21
21
-
});
22
22
-
}
23
23
-
});
24
24
-
},
25
25
-
set: (value: string[]) => {
26
26
-
set(value);
27
27
-
// Sync with translateLanguages store
28
28
-
value.forEach(code => {
29
29
-
if (!translateLanguages.languages[code]) {
30
30
-
translateLanguages.addLanguage(code, {
31
31
-
label: code,
32
32
-
native: code,
33
33
-
rtl: false,
34
34
-
display: true
35
35
-
});
36
36
-
}
37
37
-
});
38
38
-
}
39
39
-
};
40
40
-
}
41
41
-
42
42
-
export const languages = createLanguagesStore();
43
43
-
44
44
-
// Initialize the store with current translateLanguages values
45
45
-
languages.set(Object.keys(translateLanguages.languages));
···
1
1
-
import { defaultLanguages } from '$lib/utils/languages.js';
2
2
-
import languageData from '$lib/data/wikidata-languages.json';
3
3
-
4
4
-
function normalizeLanguageCode(code) {
5
5
-
return code;
6
6
-
}
7
7
-
8
8
-
let languages = $state({}); // <-- Move this outside the factory for singleton reactivity
9
9
-
10
10
-
function initializeFromStorage() {
11
11
-
if (typeof localStorage === 'undefined') {
12
12
-
// If localStorage isn't available, just use defaults
13
13
-
languages = { ...defaultLanguages };
14
14
-
return;
15
15
-
}
16
16
-
17
17
-
try {
18
18
-
// Load saved languages if they exist
19
19
-
const savedUserLangs = localStorage.getItem('user_langs');
20
20
-
if (savedUserLangs) {
21
21
-
const saved = JSON.parse(savedUserLangs);
22
22
-
languages = { ...saved };
23
23
-
} else {
24
24
-
// If no saved languages, use defaults
25
25
-
languages = { ...defaultLanguages };
26
26
-
27
27
-
// Check legacy format as fallback
28
28
-
const oldLangs = localStorage.getItem('tgt_langs');
29
29
-
if (oldLangs) {
30
30
-
const oldCodes = JSON.parse(oldLangs);
31
31
-
oldCodes.forEach(code => {
32
32
-
const normalizedCode = normalizeLanguageCode(code);
33
33
-
if (!languages[normalizedCode]) {
34
34
-
languages[normalizedCode] = {
35
35
-
label: code,
36
36
-
native: code,
37
37
-
rtl: false,
38
38
-
display: true
39
39
-
};
40
40
-
}
41
41
-
});
42
42
-
}
43
43
-
}
44
44
-
45
45
-
saveToStorage();
46
46
-
console.log('Initialized languages:', Object.keys(languages));
47
47
-
} catch (e) {
48
48
-
console.error('Failed to initialize languages from storage:', e);
49
49
-
// Fallback to defaults
50
50
-
languages = { ...defaultLanguages };
51
51
-
}
52
52
-
}
53
53
-
54
54
-
function saveToStorage() {
55
55
-
if (typeof localStorage === 'undefined') return;
56
56
-
57
57
-
try {
58
58
-
const languagesStr = JSON.stringify(languages);
59
59
-
localStorage.setItem('user_langs', languagesStr);
60
60
-
// Keep tgt_langs in sync for backward compatibility
61
61
-
localStorage.setItem('tgt_langs', JSON.stringify(Object.keys(languages)));
62
62
-
console.log('Saved languages:', Object.keys(languages));
63
63
-
} catch (e) {
64
64
-
console.error('Failed to save languages to storage:', e);
65
65
-
}
66
66
-
}
67
67
-
68
68
-
function addLanguage(code, info) {
69
69
-
if (!code || !info) {
70
70
-
throw new Error('Language code and info are required');
71
71
-
}
72
72
-
73
73
-
const normalizedCode = normalizeLanguageCode(code);
74
74
-
console.log('Adding language:', { original: code, normalized: normalizedCode });
75
75
-
76
76
-
// If it's already in the store with the normalized code, don't add it again
77
77
-
if (languages[normalizedCode]) {
78
78
-
console.log('Language already exists with normalized code:', normalizedCode);
79
79
-
return;
80
80
-
}
81
81
-
82
82
-
languages[normalizedCode] = {
83
83
-
label: info.label || code,
84
84
-
native: info.native || code,
85
85
-
rtl: info.rtl || false,
86
86
-
display: true
87
87
-
};
88
88
-
saveToStorage();
89
89
-
}
90
90
-
91
91
-
function removeLanguage(code) {
92
92
-
if (!code) {
93
93
-
throw new Error('Language code is required');
94
94
-
}
95
95
-
96
96
-
const normalizedCode = normalizeLanguageCode(code);
97
97
-
console.log('Removing language:', { original: code, normalized: normalizedCode });
98
98
-
99
99
-
delete languages[normalizedCode];
100
100
-
saveToStorage();
101
101
-
}
102
102
-
103
103
-
function getSelectedCodes() {
104
104
-
return Object.keys(languages);
105
105
-
}
106
106
-
107
107
-
function getLanguageInfo(code) {
108
108
-
const normalizedCode = normalizeLanguageCode(code);
109
109
-
return languages[normalizedCode];
110
110
-
}
111
111
-
112
112
-
function clearLanguages() {
113
113
-
// Clear all languages
114
114
-
languages = {};
115
115
-
if (typeof localStorage !== 'undefined') {
116
116
-
localStorage.removeItem('user_langs');
117
117
-
localStorage.removeItem('tgt_langs');
118
118
-
}
119
119
-
120
120
-
saveToStorage();
121
121
-
console.log('Cleared all languages');
122
122
-
}
123
123
-
124
124
-
function addDefaultLanguages() {
125
125
-
// Add default languages to the current set
126
126
-
languages = { ...languages, ...defaultLanguages };
127
127
-
saveToStorage();
128
128
-
console.log('Added default languages:', Object.keys(defaultLanguages));
129
129
-
}
130
130
-
131
131
-
function resetToDefaults() {
132
132
-
// Clear current languages and set to defaults
133
133
-
languages = { ...defaultLanguages };
134
134
-
saveToStorage();
135
135
-
console.log('Reset to defaults:', Object.keys(languages));
136
136
-
}
137
137
-
138
138
-
function toggleLanguageDisplay(code) {
139
139
-
const normalizedCode = normalizeLanguageCode(code);
140
140
-
const langInfo = languages[normalizedCode];
141
141
-
if (langInfo) {
142
142
-
languages[normalizedCode] = {
143
143
-
...langInfo,
144
144
-
display: !langInfo.display
145
145
-
};
146
146
-
saveToStorage();
147
147
-
console.log('Toggled display for:', normalizedCode, 'to:', !langInfo.display);
148
148
-
}
149
149
-
}
150
150
-
151
151
-
// Initialize on module load
152
152
-
initializeFromStorage();
153
153
-
154
154
-
export const translateLanguages = {
155
155
-
languages, // <-- Export the $state object directly
156
156
-
get selectedCodes() { return getSelectedCodes(); },
157
157
-
getLanguageInfo,
158
158
-
addLanguage,
159
159
-
removeLanguage,
160
160
-
clearLanguages,
161
161
-
addDefaultLanguages,
162
162
-
resetToDefaults,
163
163
-
toggleLanguageDisplay,
164
164
-
normalizeLanguageCode,
165
165
-
_initializeFromStorage: initializeFromStorage
166
166
-
};
···
1
1
<script lang="ts">
2
2
import type { PageData } from './$types';
3
3
-
import NewLang from '$jibs/NewLang.svelte';
3
3
+
import NewLang from '$jibs/deprecrated/NewLang.svelte';
4
4
import { translationInput } from '$lib/stores/translationStore';
5
5
6
6
interface Props {
···
46
46
}, {})
47
47
);
48
48
49
49
+
// Add a $derived for selectedCodes that always returns an array
50
50
+
let selectedCodes = $derived(() => Array.isArray(translateLanguages.selectedCodes) ? translateLanguages.selectedCodes : (Object.keys(translateLanguages.languages) ?? []));
51
51
+
49
52
function toggleLanguage(code: string) {
50
53
if (isSelected(code)) {
51
54
translateLanguages.removeLanguage(code);
···
60
63
}
61
64
62
65
function isSelected(code: string) {
63
63
-
return translateLanguages.selectedCodes.includes(code);
66
66
+
const codes = Array.isArray(selectedCodes)
67
67
+
? selectedCodes
68
68
+
: (selectedCodes && typeof selectedCodes === 'object')
69
69
+
? Object.values(selectedCodes)
70
70
+
: [];
71
71
+
return codes.includes(code);
64
72
}
65
73
66
74
function formatSpeakers(count: number | undefined) {
···
1
1
<script>
2
2
-
import { translateLanguages, createTranslateLanguages } from '$lib/stores/translateLanguages.svelte.js';
2
2
+
import { translateLanguages, createTranslateLanguages } from '$jibs/deprecrated/translateLanguages.svelte.js';
3
3
4
4
// Test data
5
5
const testLanguages = {