@plentymarkets/shop-core 1.14.2 → 1.14.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@plentymarkets/shop-core",
3
3
  "configKey": "shopCore",
4
- "version": "1.14.2",
4
+ "version": "1.14.3",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
package/dist/module.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import { defineNuxtModule, createResolver, addImports } from '@nuxt/kit';
2
2
  import { ofetch } from 'ofetch';
3
- import { mkdir, writeFile } from 'fs/promises';
3
+ import { access, mkdir, writeFile } from 'fs/promises';
4
4
  import { join } from 'path';
5
- import { existsSync } from 'fs';
5
+ import { constants } from 'fs';
6
6
 
7
7
  const fetchAllTranslations = async (url, configId) => {
8
8
  return await ofetch(
@@ -35,7 +35,9 @@ const module$1 = defineNuxtModule({
35
35
  };
36
36
  const overridesDir = resolver.resolve("./runtime/lang/overrides");
37
37
  const allLocalesForOverride = [];
38
- if (!existsSync(overridesDir)) {
38
+ try {
39
+ await access(overridesDir, constants.F_OK);
40
+ } catch {
39
41
  await mkdir(overridesDir, { recursive: true });
40
42
  }
41
43
  if (_options.apiEndpoint && _options.configId) {
@@ -51,7 +53,9 @@ const module$1 = defineNuxtModule({
51
53
  }
52
54
  }
53
55
  nuxt.hook("i18n:registerModule", (register) => {
54
- console.log(`[shop-core] Hook(i18n:registerModule) Registering language overrides for locales: "${allLocalesForOverride.join(", ")}"`);
56
+ console.log(
57
+ `[shop-core] Hook(i18n:registerModule) Registering language overrides for locales: "${allLocalesForOverride.join(", ")}"`
58
+ );
55
59
  if (allLocalesForOverride.length > 0) {
56
60
  register({
57
61
  langDir: resolver.resolve("./runtime/lang/overrides"),
@@ -1,41 +1,69 @@
1
1
  import { useRuntimeConfig } from "nuxt/app";
2
2
  import { useSdk } from "../../useSdk.js";
3
3
  import { flattenTranslations } from "./transformationHelper.js";
4
- import { createEmptyMessage } from "./messageHelper.js";
4
+ import { createEmptyMessage, cloneEmptyMessage } from "./messageHelper.js";
5
5
  import { extractKeysWithValues } from "./extractKeysWithValuesHelper.js";
6
+ const processKeysForLocale = (keysWithValues, keysMap, locale, emptyMessageTemplate) => {
7
+ const keys = Object.keys(keysWithValues);
8
+ for (let i = 0; i < keys.length; i++) {
9
+ const key = keys[i];
10
+ if (key.startsWith("translated.")) continue;
11
+ if (!keysMap.has(key)) keysMap.set(key, cloneEmptyMessage(emptyMessageTemplate));
12
+ const translations = keysMap.get(key);
13
+ translations[locale] = keysWithValues[key];
14
+ }
15
+ };
16
+ const processTranslatedKeysForLocale = (keysWithValues, keysMap, locale, emptyMessageTemplate) => {
17
+ const keys = Object.keys(keysWithValues);
18
+ for (let i = 0; i < keys.length; i++) {
19
+ const key = keys[i];
20
+ if (!keysMap.has(key)) keysMap.set(key, cloneEmptyMessage(emptyMessageTemplate));
21
+ const translations = keysMap.get(key);
22
+ if (translations[locale]) {
23
+ translations[locale].value = keysWithValues[key].value;
24
+ translations[locale].input = keysWithValues[key].input;
25
+ } else {
26
+ translations[locale] = keysWithValues[key];
27
+ }
28
+ }
29
+ };
30
+ const processBackendTranslations = (translations, keysMap, lang, emptyMessageTemplate) => {
31
+ const keys = Object.keys(translations);
32
+ for (let i = 0; i < keys.length; i++) {
33
+ const key = keys[i];
34
+ const value = translations[key];
35
+ if (!keysMap.has(key)) keysMap.set(key, cloneEmptyMessage(emptyMessageTemplate));
36
+ const localeTranslations = keysMap.get(key);
37
+ if (localeTranslations[lang]) {
38
+ localeTranslations[lang].isDeployed = localeTranslations[lang].value === value;
39
+ localeTranslations[lang].value = value;
40
+ localeTranslations[lang].input = value;
41
+ } else {
42
+ localeTranslations[lang] = { value, input: value, isDeployed: false };
43
+ }
44
+ }
45
+ };
6
46
  export const loadDefaultKeys = async (keysMap, $i18n) => {
7
- for (const locale of $i18n.availableLocales) {
47
+ const locales = $i18n.availableLocales;
48
+ const emptyMessageTemplate = createEmptyMessage(locales);
49
+ for (let i = 0; i < locales.length; i++) {
50
+ const locale = locales[i];
8
51
  await $i18n.loadLocaleMessages(locale);
9
52
  const messages = $i18n.getLocaleMessage(locale);
10
53
  const keysWithValues = extractKeysWithValues(messages);
11
- for (const [key, value] of Object.entries(keysWithValues)) {
12
- if (key.startsWith("translated.")) continue;
13
- if (!keysMap.has(key)) {
14
- keysMap.set(key, createEmptyMessage($i18n.availableLocales));
15
- }
16
- const translations = keysMap.get(key);
17
- translations[locale] = value;
18
- }
54
+ processKeysForLocale(keysWithValues, keysMap, locale, emptyMessageTemplate);
19
55
  }
20
56
  };
21
57
  export const loadTranslatedKeys = (keysMap, $i18n) => {
22
- for (const locale of $i18n.availableLocales) {
58
+ const locales = $i18n.availableLocales;
59
+ const emptyMessageTemplate = createEmptyMessage(locales);
60
+ for (let i = 0; i < locales.length; i++) {
61
+ const locale = locales[i];
23
62
  const messages = $i18n.getLocaleMessage(locale);
24
63
  const translatedMessages = messages["translated"];
25
64
  if (!translatedMessages) continue;
26
65
  const keysWithValues = extractKeysWithValues(translatedMessages);
27
- for (const [key, value] of Object.entries(keysWithValues)) {
28
- if (!keysMap.has(key)) {
29
- keysMap.set(key, createEmptyMessage($i18n.availableLocales));
30
- }
31
- const translations = keysMap.get(key);
32
- if (translations[locale]) {
33
- translations[locale].value = value.value;
34
- translations[locale].input = value.input;
35
- } else {
36
- translations[locale] = value;
37
- }
38
- }
66
+ processTranslatedKeysForLocale(keysWithValues, keysMap, locale, emptyMessageTemplate);
39
67
  }
40
68
  };
41
69
  export const loadKeysFromBackend = async (keysMap, $i18n, backendLanguages) => {
@@ -45,25 +73,13 @@ export const loadKeysFromBackend = async (keysMap, $i18n, backendLanguages) => {
45
73
  if (!configId) return;
46
74
  const { data } = await useSdk().plentysystems.getAllTranslations({ configId });
47
75
  const flattened = flattenTranslations(data);
48
- for (const [lang, translations] of Object.entries(flattened)) {
76
+ const emptyMessageTemplate = createEmptyMessage($i18n.availableLocales);
77
+ const langs = Object.keys(flattened);
78
+ for (let i = 0; i < langs.length; i++) {
79
+ const lang = langs[i];
80
+ const translations = flattened[lang];
49
81
  if (backendLanguages && Object.keys(translations).length > 0) backendLanguages.add(lang);
50
- for (const [key, value] of Object.entries(translations)) {
51
- if (!keysMap.has(key)) {
52
- keysMap.set(key, createEmptyMessage($i18n.availableLocales));
53
- }
54
- const localeTranslations = keysMap.get(key);
55
- if (localeTranslations[lang]) {
56
- localeTranslations[lang].isDeployed = localeTranslations[lang].value === value;
57
- localeTranslations[lang].value = value;
58
- localeTranslations[lang].input = value;
59
- } else {
60
- localeTranslations[lang] = {
61
- value,
62
- input: value,
63
- isDeployed: false
64
- };
65
- }
66
- }
82
+ processBackendTranslations(translations, keysMap, lang, emptyMessageTemplate);
67
83
  }
68
84
  } catch {
69
85
  }
@@ -8,4 +8,14 @@ export declare const isCompiledMessage: (value: unknown) => boolean;
8
8
  * Create an empty message object for all locales
9
9
  * @param availableLocales
10
10
  */
11
- export declare const createEmptyMessage: (availableLocales: string[]) => {};
11
+ export declare const createEmptyMessage: (availableLocales: string[]) => Record<string, {
12
+ value: string;
13
+ input: string;
14
+ isDeployed: boolean;
15
+ }>;
16
+ /**
17
+ * Clone an empty message template with all locale properties
18
+ * More efficient than creating a new message for each key
19
+ * @param template - The template message object to clone
20
+ */
21
+ export declare const cloneEmptyMessage: (template: Record<string, any>) => Record<string, any>;
@@ -2,16 +2,25 @@ export const isCompiledMessage = (value) => {
2
2
  return typeof value === "object" && value !== null && ("loc" in value && typeof value.loc === "object" && value.loc !== null && "source" in value.loc && typeof value.loc.source === "string" || "b" in value && typeof value.b === "object" && value.b !== null && "s" in value.b && typeof value.b.s === "string");
3
3
  };
4
4
  export const createEmptyMessage = (availableLocales) => {
5
- let data = {};
5
+ const data = {};
6
6
  for (const locale of availableLocales) {
7
- data = {
8
- ...data,
9
- [locale]: {
10
- value: "",
11
- input: "",
12
- isDeployed: true
13
- }
14
- };
7
+ data[locale] = { value: "", input: "", isDeployed: true };
15
8
  }
16
9
  return data;
17
10
  };
11
+ export const cloneEmptyMessage = (template) => {
12
+ const clone = {};
13
+ const locales = Object.keys(template);
14
+ const length = locales.length;
15
+ for (let i = 0; i < length; i++) {
16
+ const locale = locales[i];
17
+ const source = template[locale];
18
+ clone[locale] = {
19
+ value: source.value,
20
+ input: source.input,
21
+ isDeployed: source.isDeployed,
22
+ ...source.default !== void 0 && { default: source.default }
23
+ };
24
+ }
25
+ return clone;
26
+ };
@@ -1,4 +1,4 @@
1
- import type { TranslationObject } from "@plentymarkets/shop-api";
1
+ import type { TranslationObject } from '@plentymarkets/shop-api';
2
2
  /**
3
3
  * Flatten nested translation objects into dot notation
4
4
  * e.g. { module: { key: 'value' } } => { 'module.key': 'value' }
@@ -17,18 +17,24 @@ export const flattenTranslations = (data) => {
17
17
  }
18
18
  return result;
19
19
  };
20
+ const navigateAndCreatePath = (root, parts) => {
21
+ let current = root;
22
+ const lastIndex = parts.length - 1;
23
+ for (let i = 0; i < lastIndex; i++) {
24
+ const part = parts[i];
25
+ if (!current[part]) current[part] = {};
26
+ current = current[part];
27
+ }
28
+ return current;
29
+ };
20
30
  export const unflattenTranslations = (flat) => {
21
31
  const result = {};
22
- for (const [key, value] of Object.entries(flat)) {
32
+ const entries = Object.entries(flat);
33
+ for (let i = 0; i < entries.length; i++) {
34
+ const [key, value] = entries[i];
23
35
  const parts = key.split(".");
24
- let current = result;
25
- for (let i = 0; i < parts.length - 1; i++) {
26
- const part = parts[i];
27
- if (!current[part]) current[part] = {};
28
- current = current[part];
29
- }
30
- const lastPart = parts[parts.length - 1];
31
- current[lastPart] = value;
36
+ const target = navigateAndCreatePath(result, parts);
37
+ target[parts[parts.length - 1]] = value;
32
38
  }
33
39
  return result;
34
40
  };
@@ -4,7 +4,7 @@ export declare const useEditorLocalizationKeys: () => {
4
4
  checkHasUnsavedChanges: () => boolean;
5
5
  collectChangedTranslations: () => Record<string, Record<string, string>>;
6
6
  loadKeys: () => Promise<void>;
7
- filterKeys: (searchTerm: string, activeLocales: string[]) => void;
7
+ filterKeys: (searchTerm: string, activeLocales: string[], showOnlyMissing?: boolean) => void;
8
8
  getTranslatedCount: (locale: string) => {
9
9
  translated: number;
10
10
  undeployed: number;
@@ -14,6 +14,7 @@ export declare const useEditorLocalizationKeys: () => {
14
14
  getKeyFromFullKey: (key: string) => string;
15
15
  saveLocalizations: () => Promise<void>;
16
16
  keys: import("vue").Ref<MultilingualKeysState[], MultilingualKeysState[]>;
17
+ keysMap: import("vue").Ref<Map<string, MultilingualKeysState>, Map<string, MultilingualKeysState>>;
17
18
  filteredKeys: import("vue").Ref<MultilingualKeysState[] | null, MultilingualKeysState[] | null>;
18
19
  drawerOpen: import("vue").Ref<boolean, boolean>;
19
20
  hasChanges: import("vue").Ref<boolean, boolean>;
@@ -4,9 +4,114 @@ import { loadDefaultKeys, loadTranslatedKeys, loadKeysFromBackend } from "./help
4
4
  import { useSdk, useNotification, useEditorLocalizationLocales } from "#imports";
5
5
  import { allLanguages } from "./useEditorLocalizationLocales.js";
6
6
  import { unflattenTranslations } from "./helpers/transformationHelper.js";
7
+ const containsSearchTerm = (text, searchQuery) => {
8
+ return text.toLowerCase().indexOf(searchQuery) !== -1;
9
+ };
10
+ const hasMatchingTranslation = (translations, searchQuery, activeLocalesSet) => {
11
+ for (const locale of activeLocalesSet) {
12
+ const translation = translations[locale];
13
+ if (translation && containsSearchTerm(translation.input, searchQuery)) {
14
+ return true;
15
+ }
16
+ }
17
+ return false;
18
+ };
19
+ const matchesSearchQuery = (keyEntry, searchQuery, activeLocalesSet) => {
20
+ if (containsSearchTerm(keyEntry.key, searchQuery)) return true;
21
+ return hasMatchingTranslation(keyEntry.translations, searchQuery, activeLocalesSet);
22
+ };
23
+ const hasMissingTranslations = (keyEntry, activeLocalesSet) => {
24
+ for (const locale of activeLocalesSet) {
25
+ const translation = keyEntry.translations[locale];
26
+ if (!translation || !translation.value || translation.value.trim().length === 0) return true;
27
+ }
28
+ return false;
29
+ };
30
+ const processKeyChanges = (keyState, selectedLocalesSet, translationsByLocale) => {
31
+ for (const locale in keyState.translations) {
32
+ if (!selectedLocalesSet.has(locale)) continue;
33
+ const translation = keyState.translations[locale];
34
+ if (translation && translation.input !== translation.value) {
35
+ if (!translationsByLocale[locale]) translationsByLocale[locale] = {};
36
+ translationsByLocale[locale][keyState.key] = translation.input;
37
+ }
38
+ }
39
+ };
40
+ const keyHasUnsavedChanges = (keyState, selectedLocalesSet) => {
41
+ for (const locale in keyState.translations) {
42
+ if (!selectedLocalesSet.has(locale)) continue;
43
+ const translation = keyState.translations[locale];
44
+ if (translation && translation.input !== translation.value) return true;
45
+ }
46
+ return false;
47
+ };
48
+ const collectChanges = (keys, selectedLocalesSet) => {
49
+ const translationsByLocale = {};
50
+ for (let i = 0; i < keys.length; i++) {
51
+ processKeyChanges(keys[i], selectedLocalesSet, translationsByLocale);
52
+ }
53
+ return translationsByLocale;
54
+ };
55
+ const hasUnsavedChanges = (keys, selectedLocalesSet) => {
56
+ for (let i = 0; i < keys.length; i++) {
57
+ if (keyHasUnsavedChanges(keys[i], selectedLocalesSet)) return true;
58
+ }
59
+ return false;
60
+ };
61
+ const saveLanguageTranslations = async (language, configId, translations, backendLanguages) => {
62
+ try {
63
+ const nestedTranslations = unflattenTranslations(translations);
64
+ const languageExistsInBackend = backendLanguages.has(language);
65
+ const sdk = useSdk().plentysystems;
66
+ const saveMethod = languageExistsInBackend ? sdk.patchMergeTranslations : sdk.doCreateTranslations;
67
+ await saveMethod({ configId, language, translations: nestedTranslations });
68
+ if (!languageExistsInBackend) backendLanguages.add(language);
69
+ return { language, success: true };
70
+ } catch (error) {
71
+ return { language, success: false, error };
72
+ }
73
+ };
74
+ const updateLocalStateAfterSave = (keys, language, savedTranslations) => {
75
+ for (let i = 0; i < keys.length; i++) {
76
+ const keyState = keys[i];
77
+ const translation = keyState.translations[language];
78
+ if (translation && savedTranslations[keyState.key] !== void 0) {
79
+ translation.isDeployed = true;
80
+ translation.value = translation.input;
81
+ }
82
+ }
83
+ };
84
+ const notifySaveResults = (results) => {
85
+ const { send } = useNotification();
86
+ const successful = [];
87
+ const failed = [];
88
+ for (let i = 0; i < results.length; i++) {
89
+ const result = results[i];
90
+ const displayName = allLanguages[result.language] || result.language.toUpperCase();
91
+ if (result.success) {
92
+ successful.push(displayName);
93
+ } else {
94
+ failed.push(displayName);
95
+ }
96
+ }
97
+ if (successful.length > 0) {
98
+ send({
99
+ message: `Translations for ${successful.join(", ")} saved successfully`,
100
+ type: "positive"
101
+ });
102
+ }
103
+ if (failed.length > 0) {
104
+ send({
105
+ message: `Failed to save translations for ${failed.join(", ")}`,
106
+ type: "negative",
107
+ persist: true
108
+ });
109
+ }
110
+ };
7
111
  export const useEditorLocalizationKeys = () => {
8
112
  const state = useState("useEditorLocalizationKeys", () => ({
9
113
  keys: [],
114
+ keysMap: /* @__PURE__ */ new Map(),
10
115
  filteredKeys: null,
11
116
  drawerOpen: false,
12
117
  hasChanges: false,
@@ -27,36 +132,40 @@ export const useEditorLocalizationKeys = () => {
27
132
  key,
28
133
  translations
29
134
  })).sort((a, b) => a.key.localeCompare(b.key));
135
+ state.value.keysMap.clear();
136
+ for (let i = 0; i < state.value.keys.length; i++) {
137
+ const keyState = state.value.keys[i];
138
+ state.value.keysMap.set(keyState.key, keyState);
139
+ }
30
140
  state.value.loading = false;
31
141
  state.value.drawerOpen = true;
32
142
  };
33
- const filterKeys = (searchTerm, activeLocales) => {
34
- if (searchTerm.trim().length === 0) {
143
+ const filterKeys = (searchTerm, activeLocales, showOnlyMissing = false) => {
144
+ if (searchTerm.trim().length === 0 && !showOnlyMissing) {
35
145
  state.value.filteredKeys = null;
36
146
  return;
37
147
  }
38
148
  const searchQuery = searchTerm.trim().toLowerCase();
39
- state.value.filteredKeys = state.value.keys.filter((keyEntry) => {
40
- if (keyEntry.key.toLowerCase().includes(searchQuery)) {
41
- return true;
42
- }
43
- return activeLocales.some((locale) => {
44
- const translation = keyEntry.translations[locale];
45
- if (!translation) return false;
46
- return translation.input.toLowerCase().includes(searchQuery);
47
- });
48
- });
149
+ const activeLocalesSet = new Set(activeLocales);
150
+ const filtered = [];
151
+ const hasSearchTerm = searchQuery.length > 0;
152
+ for (let i = 0; i < state.value.keys.length; i++) {
153
+ const keyEntry = state.value.keys[i];
154
+ const matchesSearch = !hasSearchTerm || matchesSearchQuery(keyEntry, searchQuery, activeLocalesSet);
155
+ const matchesMissing = !showOnlyMissing || hasMissingTranslations(keyEntry, activeLocalesSet);
156
+ if (matchesSearch && matchesMissing) filtered.push(keyEntry);
157
+ }
158
+ state.value.filteredKeys = filtered;
49
159
  };
50
160
  const getTranslatedCount = (locale) => {
51
161
  let translatedCount = 0;
52
162
  let undeployedCount = 0;
53
- let totalCount = state.value.keys.length;
54
- for (const keyState of state.value.keys) {
55
- if (keyState.translations[locale] && keyState.translations[locale].value.length > 0) {
163
+ const totalCount = state.value.keys.length;
164
+ for (let i = 0; i < totalCount; i++) {
165
+ const translation = state.value.keys[i].translations[locale];
166
+ if (translation && translation.value.length > 0) {
56
167
  translatedCount++;
57
- if (!keyState.translations[locale].isDeployed) {
58
- undeployedCount++;
59
- }
168
+ if (!translation.isDeployed) undeployedCount++;
60
169
  }
61
170
  }
62
171
  return {
@@ -77,38 +186,17 @@ export const useEditorLocalizationKeys = () => {
77
186
  const collectChangedTranslations = () => {
78
187
  const { selectedLocales } = useEditorLocalizationLocales();
79
188
  if (!selectedLocales.value || selectedLocales.value.length === 0) return {};
80
- const translationsByLocale = {};
81
189
  const selectedLocalesSet = new Set(selectedLocales.value);
82
- for (let i = 0; i < state.value.keys.length; i++) {
83
- const keyState = state.value.keys[i];
84
- for (const locale in keyState.translations) {
85
- if (!selectedLocalesSet.has(locale)) continue;
86
- const translation = keyState.translations[locale];
87
- if (translation && translation.input !== translation.value) {
88
- if (!translationsByLocale[locale]) translationsByLocale[locale] = {};
89
- translationsByLocale[locale][keyState.key] = translation.input;
90
- }
91
- }
92
- }
93
- return translationsByLocale;
190
+ return collectChanges(state.value.keys, selectedLocalesSet);
94
191
  };
95
192
  const checkHasUnsavedChanges = () => {
96
193
  const { selectedLocales } = useEditorLocalizationLocales();
97
194
  if (!selectedLocales.value || selectedLocales.value.length === 0) return false;
98
195
  const selectedLocalesSet = new Set(selectedLocales.value);
99
- for (const keyState of state.value.keys) {
100
- for (const locale in keyState.translations) {
101
- if (!selectedLocalesSet.has(locale)) continue;
102
- const translation = keyState.translations[locale];
103
- if (translation && translation.input !== translation.value) {
104
- return true;
105
- }
106
- }
107
- }
108
- return false;
196
+ return hasUnsavedChanges(state.value.keys, selectedLocalesSet);
109
197
  };
110
198
  const updateTranslationInput = (key, locale, newInput) => {
111
- const keyState = state.value.keys.find((k) => k.key === key);
199
+ const keyState = state.value.keysMap.get(key);
112
200
  if (!keyState || !keyState.translations[locale]) return;
113
201
  const translation = keyState.translations[locale];
114
202
  translation.input = newInput;
@@ -118,47 +206,6 @@ export const useEditorLocalizationKeys = () => {
118
206
  state.value.hasChanges = checkHasUnsavedChanges();
119
207
  }
120
208
  };
121
- const saveLanguageTranslations = async (language, configId, translations) => {
122
- try {
123
- const nestedTranslations = unflattenTranslations(translations);
124
- const languageExistsInBackend = state.value.backendLanguages.has(language);
125
- const sdk = useSdk().plentysystems;
126
- const saveMethod = languageExistsInBackend ? sdk.patchMergeTranslations : sdk.doCreateTranslations;
127
- await saveMethod({ configId, language, translations: nestedTranslations });
128
- if (!languageExistsInBackend) state.value.backendLanguages.add(language);
129
- return { language, success: true };
130
- } catch (error) {
131
- return { language, success: false, error };
132
- }
133
- };
134
- const updateLocalStateAfterSave = (language, savedTranslations) => {
135
- for (let i = 0; i < state.value.keys.length; i++) {
136
- const keyState = state.value.keys[i];
137
- const translation = keyState.translations[language];
138
- if (translation && savedTranslations[keyState.key] !== void 0) {
139
- translation.isDeployed = true;
140
- translation.value = translation.input;
141
- }
142
- }
143
- };
144
- const notifySaveResults = (results) => {
145
- const { send } = useNotification();
146
- const successful = results.filter((r) => r.success).map((r) => allLanguages[r.language] || r.language.toUpperCase());
147
- const failed = results.filter((r) => !r.success).map((r) => allLanguages[r.language] || r.language.toUpperCase());
148
- if (successful.length > 0) {
149
- send({
150
- message: `Translations for ${successful.join(", ")} saved successfully`,
151
- type: "positive"
152
- });
153
- }
154
- if (failed.length > 0) {
155
- send({
156
- message: `Failed to save translations for ${failed.join(", ")}`,
157
- type: "negative",
158
- persist: true
159
- });
160
- }
161
- };
162
209
  const saveLocalizations = async () => {
163
210
  const config = useRuntimeConfig().public.shopCore;
164
211
  const configId = config?.configId;
@@ -169,11 +216,12 @@ export const useEditorLocalizationKeys = () => {
169
216
  state.value.loading = true;
170
217
  try {
171
218
  const savePromises = localesToSave.map(
172
- (language) => saveLanguageTranslations(language, configId, translationsByLocale[language])
219
+ (language) => saveLanguageTranslations(language, configId, translationsByLocale[language], state.value.backendLanguages)
173
220
  );
174
221
  const results = await Promise.all(savePromises);
175
222
  results.forEach((result) => {
176
- if (result.success) updateLocalStateAfterSave(result.language, translationsByLocale[result.language]);
223
+ if (result.success)
224
+ updateLocalStateAfterSave(state.value.keys, result.language, translationsByLocale[result.language]);
177
225
  });
178
226
  notifySaveResults(results);
179
227
  state.value.hasChanges = false;
@@ -42,22 +42,25 @@ export const useEditorLocalizationLocales = () => {
42
42
  }
43
43
  };
44
44
  const removeLocale = (locale) => {
45
- state.value.selectedLocales = state.value.selectedLocales.filter((l) => l !== locale);
45
+ const index = state.value.selectedLocales.indexOf(locale);
46
+ if (index > -1) state.value.selectedLocales.splice(index, 1);
46
47
  saveLocales();
47
48
  };
48
49
  const toggleLocale = (locale) => {
49
- if (state.value.selectedLocales.includes(locale)) {
50
- removeLocale(locale);
51
- } else {
52
- selectLocale(locale);
53
- }
50
+ const index = state.value.selectedLocales.indexOf(locale);
51
+ index > -1 ? state.value.selectedLocales.splice(index, 1) : state.value.selectedLocales.push(locale);
54
52
  saveLocales();
55
53
  };
56
54
  const initializeLocales = () => {
57
55
  const selectedLocales = localStorage.getItem("editorLocalizationSelectedLocales");
58
56
  if (selectedLocales) {
59
57
  const parsedLocales = JSON.parse(selectedLocales);
60
- state.value.selectedLocales = parsedLocales.filter((l) => allLanguages.hasOwnProperty(l));
58
+ const validLanguages = new Set(Object.keys(allLanguages));
59
+ const validLocales = [];
60
+ for (let i = 0; i < parsedLocales.length; i++) {
61
+ if (validLanguages.has(parsedLocales[i])) validLocales.push(parsedLocales[i]);
62
+ }
63
+ state.value.selectedLocales = validLocales;
61
64
  } else {
62
65
  state.value.selectedLocales = ["de", "en"];
63
66
  }
@@ -1,2 +1,3 @@
1
1
  import type { AxiosRequestConfig } from 'axios';
2
+ export declare const handleHttpError: (error: unknown) => never;
2
3
  export declare const httpClient: (url: string, params: unknown, config: AxiosRequestConfig<unknown> | undefined) => Promise<any>;
@@ -1,6 +1,6 @@
1
1
  import axios from "axios";
2
2
  import { ApiError } from "@plentymarkets/shop-api";
3
- const handleHttpError = (error) => {
3
+ export const handleHttpError = (error) => {
4
4
  const axiosError = error;
5
5
  const data = axiosError?.response?.data?.data || axiosError?.response?.data;
6
6
  const events = axiosError?.response?.data?.events;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plentymarkets/shop-core",
3
- "version": "1.14.2",
3
+ "version": "1.14.3",
4
4
  "description": "Core module for PlentyONE Shop",
5
5
  "repository": {
6
6
  "type": "git",
@@ -45,7 +45,7 @@
45
45
  "test:types": "vue-tsc --noEmit"
46
46
  },
47
47
  "dependencies": {
48
- "@plentymarkets/shop-api": "^0.148.0",
48
+ "@plentymarkets/shop-api": "^0.148.1",
49
49
  "@vue-storefront/sdk": "^3.4.1",
50
50
  "cookie": "^1.0.2",
51
51
  "js-sha256": "^0.11.0",