Skip to content

Commit 7544f40

Browse files
committed
feat: zip changes
1 parent bd7421d commit 7544f40

File tree

11 files changed

+228
-53
lines changed

11 files changed

+228
-53
lines changed

app/app.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ const items: NavigationMenuItem[] = [
103103
];
104104
105105
const uiStore = useUIStore();
106+
const translationStore = useTranslationStore();
106107
107108
onMounted(() => {
108109
if (
@@ -118,5 +119,11 @@ onMounted(() => {
118119
) {
119120
uiStore.nwpTranslations = parseTranslationFile(uiStore.nwpString);
120121
}
122+
123+
typedKeys(translationStore.input).forEach((key) => {
124+
if (translationStore.input[key] && !translationStore.translations[key]) {
125+
translationStore.setTranslations(translationStore.input, key);
126+
}
127+
});
121128
});
122129
</script>

app/components/JsonChanges.vue

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<template>
2+
<UPageCard v-if="isDifferent" :title="label">
3+
<template v-if="isDifferent">
4+
<DiffViewer :new-string="translations" :old-string="inputTranslations" />
5+
<UButton
6+
class="w-fit"
7+
color="error"
8+
:label="`Reset ${label.toLowerCase()}`"
9+
@click="resetUI"
10+
/>
11+
</template>
12+
<p v-else>Geen veranderde {{ label.toLowerCase() }} gevonden.</p>
13+
</UPageCard>
14+
</template>
15+
16+
<script setup lang="ts">
17+
const props = defineProps<{
18+
type: "literature" | "outlines" | "songs" | "tips";
19+
}>();
20+
21+
const translationStore = useTranslationStore();
22+
23+
const label = computed(() => {
24+
switch (props.type) {
25+
case "literature":
26+
return "Lectuur";
27+
case "outlines":
28+
return "Lezingen";
29+
case "songs":
30+
return "Liederen";
31+
case "tips":
32+
return "Tips";
33+
default:
34+
return "Onbekend";
35+
}
36+
});
37+
38+
const inputTranslations = computed(() => {
39+
return JSON.stringify(translationStore.input[props.type], null, 2);
40+
});
41+
42+
const translations = computed(() => {
43+
return JSON.stringify(translationStore.translations[props.type], null, 2);
44+
});
45+
46+
const isDifferent = computed(() => {
47+
return inputTranslations.value !== translations.value;
48+
});
49+
50+
const resetUI = () => {
51+
translationStore.setTranslations({ ...translationStore.input });
52+
};
53+
</script>

app/components/UIChanges.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<UPageCard :title="`${type} UI veranderingen`">
2+
<UPageCard v-if="isDifferent" :title="`${type} UI veranderingen`">
33
<template v-if="isDifferent">
44
<DiffViewer :new-string="translations" :old-string="remoteTranslations" />
55
<UButton

app/pages/export.vue

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,22 @@
44
<UPageBody>
55
<UIChanges type="NWS" />
66
<UIChanges type="NWP" />
7+
<JsonChanges type="literature" />
8+
<JsonChanges type="outlines" />
9+
<JsonChanges type="songs" />
10+
<JsonChanges type="tips" />
711
<UPageCard title="Bestanden">
812
<div class="flex flex-wrap gap-2">
13+
<UButton
14+
class="w-fit"
15+
label="Zipbestand met veranderingen"
16+
@click="exportChangedFiles"
17+
/>
918
<UButton
1019
v-for="file in jsonFiles"
1120
:key="file.name"
1221
class="w-fit"
22+
color="neutral"
1323
:label="`${file.name}.json`"
1424
@click="exportJSON(file.name, file.data)"
1525
/>
@@ -45,22 +55,29 @@ const { showError } = useFlash();
4555
const jsonFiles = computed(() => {
4656
return [
4757
{
58+
changed: translationStore.changedGroups.includes("literature"),
4859
data: translationStore.translations.literature,
4960
name: "Literature",
5061
},
5162
{
63+
changed: translationStore.changedGroups.includes("outlines"),
5264
data: translationStore.translations.outlines,
5365
name: "Outlines",
5466
},
5567
{
68+
changed:
69+
JSON.stringify(uiStore.translations) !==
70+
JSON.stringify(uiStore.remoteTranslations),
5671
data: uiStore.translations,
5772
name: "ProgramUI",
5873
},
5974
{
75+
changed: translationStore.changedGroups.includes("songs"),
6076
data: translationStore.translations.songs,
6177
name: "Songs",
6278
},
6379
{
80+
changed: translationStore.changedGroups.includes("tips"),
6481
data: translationStore.translations.tips,
6582
name: "Tips",
6683
},
@@ -84,6 +101,40 @@ const exportJSON = <T,>(name: string, data: T) => {
84101
}
85102
};
86103
104+
const exportChangedFiles = async () => {
105+
try {
106+
const blob = await $fetch<Blob>("/api/export", {
107+
body: {
108+
files: jsonFiles.value
109+
.filter(({ changed }) => changed)
110+
.map((file) => ({
111+
data: file.data,
112+
name: file.name + ".json",
113+
})),
114+
},
115+
method: "POST",
116+
responseType: "blob",
117+
});
118+
119+
// Create a download link and trigger it
120+
const url = URL.createObjectURL(blob);
121+
const link = document.createElement("a");
122+
link.href = url;
123+
link.download = "translations.zip";
124+
link.click();
125+
126+
// Clean up
127+
URL.revokeObjectURL(url);
128+
link.remove();
129+
} catch (e) {
130+
console.error(e);
131+
showError({
132+
description: "Kon zipbestand niet downloaden.",
133+
id: "export-zip-error",
134+
});
135+
}
136+
};
137+
87138
const title = "Exporteren";
88139
const description = "Exporteer op deze pagina de vertaalde teksten.";
89140

app/pages/import.vue

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
accept="application/json"
2121
:disabled="originalFiles.length > 0"
2222
label="Importeer vanuit lokale bestanden"
23-
@change="loadFiles(originalFiles, 'original')"
2423
/>
2524
<ImportForm v-model="originals" no-nwp />
2625
</UPageCard>
@@ -35,7 +34,6 @@
3534
accept="application/json"
3635
:disabled="translationFiles.length > 0"
3736
label="Importeer vanuit lokale bestanden"
38-
@change="loadFiles(translationFiles, 'translation')"
3937
/>
4038
<ImportForm v-model="translations" />
4139
</UPageCard>
@@ -58,7 +56,7 @@ const originals = ref<Output>({
5856
const translations = ref<Output>({
5957
nwp: nwpString.value,
6058
ui: translationsString.value,
61-
...translationStore.translations,
59+
...translationStore.input,
6260
});
6361
6462
const { showSuccess } = useFlash();
@@ -94,6 +92,7 @@ watch(translations, (val) => {
9492
uiStore.nwpTranslations = val.nwp ? parseTranslationFile(val.nwp) : undefined;
9593
9694
// JSON
95+
translationStore.setInput(val);
9796
translationStore.setTranslations(val);
9897
9998
showSuccess({
@@ -179,9 +178,21 @@ const loadFile = async (file: File, type: "original" | "translation") => {
179178
}
180179
};
181180
182-
const loadFiles = async (files: File[], type: "original" | "translation") => {
183-
if (files.length === 0) return;
181+
watch(originalFiles, (files) => {
182+
loadFiles(files, "original");
183+
});
184+
185+
watch(translationFiles, (files) => {
186+
loadFiles(files, "translation");
187+
});
188+
189+
const loadFiles = async (
190+
files: File[] | null | undefined,
191+
type: "original" | "translation",
192+
) => {
193+
if (!files || files.length === 0) return;
184194
if (files.some((file) => file.type !== "application/json")) {
195+
console.log("some not json");
185196
if (type === "original") {
186197
originalFiles.value = originalFiles.value.filter(
187198
(file) => file.type === "application/json",

app/pages/translate/songs/index.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,14 @@ const translateSongs = async () => {
5050
"https://b.jw-cdn.org/apis/pub-media/GETPUBMEDIALINKS?pub=sjjm&langwritten=O&fileformat=MP3",
5151
);
5252
53+
const overwrites: Record<number, string> = {
54+
160: "Goed nieuws!",
55+
};
56+
5357
const songs = res.files.O.MP3.filter((s) => s.track <= 500).map(
5458
(song): Song => ({
5559
number: song.track.toString(),
56-
title: song.title.replace(/^\d+\. /, ""),
60+
title: overwrites[song.track] ?? song.title.replace(/^\d+\. /, ""),
5761
}),
5862
);
5963

app/stores/translation.ts

Lines changed: 57 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,41 @@
11
export type TranslationKey = keyof State;
22

33
type State = {
4-
literature: { originals?: Literature; translations?: Literature };
5-
outlines: { originals?: Outlines; translations?: Outlines };
6-
songs: { originals?: Songs; translations?: Songs };
7-
tips: { originals?: Tips; translations?: Tips };
4+
literature: {
5+
input?: Literature;
6+
originals?: Literature;
7+
translations?: Literature;
8+
};
9+
outlines: { input?: Outlines; originals?: Outlines; translations?: Outlines };
10+
songs: { input?: Songs; originals?: Songs; translations?: Songs };
11+
tips: { input?: Tips; originals?: Tips; translations?: Tips };
812
};
913

1014
export const useTranslationStore = defineStore("translation", {
1115
actions: {
12-
encodeOriginals() {
13-
return {
14-
literature: this.literature.originals
15-
? JSON.stringify(this.literature.originals, null, 2)
16-
: undefined,
17-
outlines: this.outlines.originals
18-
? JSON.stringify(this.outlines.originals, null, 2)
19-
: undefined,
20-
songs: this.songs.originals
21-
? JSON.stringify(this.songs.originals, null, 2)
22-
: undefined,
23-
tips: this.tips.originals
24-
? JSON.stringify(this.tips.originals, null, 2)
25-
: undefined,
26-
};
27-
},
28-
encodeTranslations() {
29-
return {
30-
literature: this.literature.translations
31-
? JSON.stringify(this.literature.translations, null, 2)
32-
: undefined,
33-
outlines: this.outlines.translations
34-
? JSON.stringify(this.outlines.translations, null, 2)
35-
: undefined,
36-
songs: this.songs.translations
37-
? JSON.stringify(this.songs.translations, null, 2)
38-
: undefined,
39-
tips: this.tips.translations
40-
? JSON.stringify(this.tips.translations, null, 2)
41-
: undefined,
42-
};
43-
},
4416
async fixInconsistentTips(heading: string, tips: { index: number }[]) {
4517
tips.forEach((t) => {
4618
if (!this.tips.translations?.[t.index]) return;
4719
this.tips.translations![t.index]!.heading = heading;
4820
});
4921
await new Promise((resolve) => setTimeout(resolve, 100));
5022
},
23+
setInput({
24+
literature,
25+
outlines,
26+
songs,
27+
tips,
28+
}: {
29+
literature?: Literature;
30+
outlines?: Outlines;
31+
songs?: Songs;
32+
tips?: Tips;
33+
}) {
34+
this.literature = { ...this.literature, input: literature };
35+
this.outlines = { ...this.outlines, input: outlines };
36+
this.songs = { ...this.songs, input: songs };
37+
this.tips = { ...this.tips, input: tips };
38+
},
5139
setOriginals({
5240
literature,
5341
outlines,
@@ -93,6 +81,19 @@ export const useTranslationStore = defineStore("translation", {
9381
},
9482
},
9583
getters: {
84+
changedGroups(state) {
85+
const groups: (keyof State)[] = [];
86+
typedKeys(state).forEach((group) => {
87+
if (
88+
state[group] &&
89+
JSON.stringify(state[group].input) !==
90+
JSON.stringify(state[group].translations)
91+
) {
92+
groups.push(group);
93+
}
94+
});
95+
return groups;
96+
},
9697
inconsistentTips(state) {
9798
if (!state.tips.originals?.length) return [];
9899
const headings: Record<string, { index: number; translation: string }[]> =
@@ -129,6 +130,14 @@ export const useTranslationStore = defineStore("translation", {
129130
translations: [...new Set(tips.map((t) => t.translation))],
130131
}));
131132
},
133+
input(state) {
134+
return {
135+
literature: state.literature.input,
136+
outlines: state.outlines.input,
137+
songs: state.songs.input,
138+
tips: state.tips.input,
139+
};
140+
},
132141
missingLiterature(state) {
133142
return (
134143
state.literature.originals?.filter(
@@ -180,9 +189,17 @@ export const useTranslationStore = defineStore("translation", {
180189
},
181190
persist: true,
182191
state: (): State => ({
183-
literature: { originals: undefined, translations: undefined },
184-
outlines: { originals: undefined, translations: undefined },
185-
songs: { originals: undefined, translations: undefined },
186-
tips: { originals: undefined, translations: undefined },
192+
literature: {
193+
input: undefined,
194+
originals: undefined,
195+
translations: undefined,
196+
},
197+
outlines: {
198+
input: undefined,
199+
originals: undefined,
200+
translations: undefined,
201+
},
202+
songs: { input: undefined, originals: undefined, translations: undefined },
203+
tips: { input: undefined, originals: undefined, translations: undefined },
187204
}),
188205
});

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
"@vue/test-utils": "^2.4.6",
5454
"eslint": "^9.39.2",
5555
"eslint-config-prettier": "^10.1.8",
56-
"eslint-plugin-perfectionist": "^5.4.0",
56+
"eslint-plugin-perfectionist": "^5.5.0",
5757
"eslint-plugin-prettier": "^5.5.5",
5858
"eslint-plugin-security": "^3.0.1",
5959
"happy-dom": "^20.4.0",

0 commit comments

Comments
 (0)