0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-04-01 02:51:27 -05:00

fix(web): translations (#10021)

This commit is contained in:
Michel Heusschen 2024-06-07 13:23:13 +02:00 committed by GitHub
parent f2148ddf03
commit c8f2d994c6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 73 additions and 36 deletions

View file

@ -61,12 +61,12 @@
[JobName.ThumbnailGeneration]: {
icon: mdiFileJpgBox,
title: getJobName(JobName.ThumbnailGeneration),
subtitle: $t('thumbnail_generation_job_description'),
subtitle: $t('admin.thumbnail_generation_job_description'),
},
[JobName.MetadataExtraction]: {
icon: mdiTable,
title: getJobName(JobName.MetadataExtraction),
subtitle: $t('metadata_extraction_job_description'),
subtitle: $t('admin.metadata_extraction_job_description'),
},
[JobName.Library]: {
icon: mdiLibraryShelves,
@ -78,7 +78,7 @@
[JobName.Sidecar]: {
title: getJobName(JobName.Sidecar),
icon: mdiFileXmlBox,
subtitle: $t('sidecar_job_description'),
subtitle: $t('admin.sidecar_job_description'),
allText: $t('sync').toUpperCase(),
missingText: $t('discover').toUpperCase(),
disabled: !$featureFlags.sidecar,
@ -86,13 +86,13 @@
[JobName.SmartSearch]: {
icon: mdiImageSearch,
title: getJobName(JobName.SmartSearch),
subtitle: $t('smart_search_job_description'),
subtitle: $t('admin.smart_search_job_description'),
disabled: !$featureFlags.smartSearch,
},
[JobName.DuplicateDetection]: {
icon: mdiContentDuplicate,
title: getJobName(JobName.DuplicateDetection),
subtitle: $t('duplicate_detection_job_description'),
subtitle: $t('admin.duplicate_detection_job_description'),
disabled: !$featureFlags.duplicateDetection,
},
[JobName.FaceDetection]: {
@ -114,7 +114,7 @@
[JobName.VideoConversion]: {
icon: mdiVideo,
title: getJobName(JobName.VideoConversion),
subtitle: $t('video_conversion_job_description'),
subtitle: $t('admin.video_conversion_job_description'),
},
[JobName.StorageTemplateMigration]: {
icon: mdiFolderMove,
@ -125,7 +125,7 @@
[JobName.Migration]: {
icon: mdiFolderMove,
title: getJobName(JobName.Migration),
subtitle: $t('migration_job_description'),
subtitle: $t('admin.migration_job_description'),
allowForceCommand: false,
},
};

View file

@ -5,6 +5,6 @@
Apply the current
<a href="{AppRoute.ADMIN_SETTINGS}?open=storageTemplate" class="text-immich-primary dark:text-immich-dark-primary"
>{$t('storage_template_settings')}</a
>{$t('admin.storage_template_settings')}</a
>
to previously uploaded assets

View file

@ -270,7 +270,7 @@
},
{
value: TranscodeHWAccel.Disabled,
text: $t('disabled'),
text: $t('admin.disabled'),
},
]}
isEdited={config.ffmpeg.accel !== savedConfig.ffmpeg.accel}

View file

@ -100,7 +100,7 @@
href="https://crontab.guru"
class="underline"
target="_blank"
rel="noreferrer">{$t('crontab_guru')}</a
rel="noreferrer">{$t('admin.crontab_guru')}</a
>
</p>
</svelte:fragment>

View file

@ -315,7 +315,7 @@
await handleDeleteAlbum(albumToDelete);
} catch {
notificationController.show({
message: $t('errors.errors.unable_to_delete_album'),
message: $t('errors.unable_to_delete_album'),
type: NotificationType.Error,
});
} finally {

View file

@ -25,7 +25,7 @@
<OnboardingCard>
<p class="text-xl text-immich-primary dark:text-immich-dark-primary">
{$t('storage_template_settings').toUpperCase()}
{$t('admin.storage_template_settings').toUpperCase()}
</p>
<p>

View file

@ -40,7 +40,7 @@
</script>
{#if unstack}
<MenuOption text={$t('un-stack')} icon={mdiImageMinusOutline} on:click={handleUnstack} />
<MenuOption text={$t('unstack')} icon={mdiImageMinusOutline} on:click={handleUnstack} />
{:else}
<MenuOption text={$t('stack')} icon={mdiImageMultipleOutline} on:click={handleStack} />
{/if}

View file

@ -68,7 +68,7 @@
<SettingInputField
inputType={SettingInputFieldType.NUMBER}
label={$t('duration')}
desc={$t('slideshow_duration_description')}
desc={$t('admin.slideshow_duration_description')}
min={1}
bind:value={$slideshowDelay}
/>

36
web/src/lib/i18n.spec.ts Normal file
View file

@ -0,0 +1,36 @@
import messages from '$lib/i18n/en.json';
import { exec as execCallback } from 'node:child_process';
import { promisify } from 'node:util';
import { init } from 'svelte-i18n';
type Messages = { [key: string]: string | Messages };
const exec = promisify(execCallback);
function setEmptyMessages(messages: Messages) {
const copy = { ...messages };
for (const key in copy) {
const message = copy[key];
if (typeof message === 'string') {
copy[key] = '';
} else if (typeof message === 'object') {
setEmptyMessages(message);
}
}
return copy;
}
describe('i18n', () => {
beforeEach(() => init({ fallbackLocale: 'dev' }));
test('no missing messages', async () => {
const { stdout } = await exec('npx svelte-i18n extract -c svelte.config.js "src/**/*"');
const extractedMessages: Messages = JSON.parse(stdout);
const existingMessages = setEmptyMessages(messages);
// Only translations directly using the store seem to get extracted
expect({ ...extractedMessages, ...existingMessages }).toEqual(existingMessages);
});
});

View file

@ -473,7 +473,7 @@
"info": "Info",
"interval": {
"day_at_onepm": "Every day at 1pm",
"hours": "Every {hours, plural, one {hour} other {{hours, number} hours}",
"hours": "Every {hours, plural, one {hour} other {{hours, number} hours}}",
"night_at_midnight": "Every night at midnight",
"night_at_twoam": "Every night at 2am"
},
@ -552,6 +552,7 @@
"no_shared_albums_message": "Create an album to share photos and videos with people in your network",
"not_in_any_album": "Not in any album",
"notes": "Notes",
"oauth": "OAuth",
"offline": "Offline",
"ok": "Ok",
"oldest_first": "Oldest first",

View file

@ -364,7 +364,7 @@
await deleteAlbum({ id: album.id });
await goto(backUrl);
} catch (error) {
handleError(error, $t('unable_to_delete_album'));
handleError(error, $t('errors.unable_to_delete_album'));
} finally {
viewMode = ViewMode.VIEW;
}

View file

@ -209,7 +209,7 @@
type: NotificationType.Info,
});
} catch (error) {
handleError(error, $t('unable_to_save_name'));
handleError(error, $t('errors.unable_to_save_name'));
}
if (personToBeMergedIn.name !== personName && edittingPerson.id === personToBeMergedIn.id) {
/*
@ -235,7 +235,7 @@
// trigger reactivity
people = people;
} catch (error) {
handleError(error, $t('unable_to_save_name'));
handleError(error, $t('errors.unable_to_save_name'));
}
}
};
@ -279,7 +279,7 @@
type: NotificationType.Info,
});
} catch (error) {
handleError(error, $t('unable_to_hide_person'));
handleError(error, $t('errors.unable_to_hide_person'));
}
};
@ -350,7 +350,7 @@
type: NotificationType.Info,
});
} catch (error) {
handleError(error, $t('unable_to_save_name'));
handleError(error, $t('errors.unable_to_save_name'));
}
};
@ -377,7 +377,7 @@
type: NotificationType.Info,
});
} catch (error) {
handleError(error, $t('unable_to_save_name'));
handleError(error, $t('errors.unable_to_save_name'));
}
};

View file

@ -189,7 +189,7 @@
await goto(previousRoute, { replaceState: true });
} catch (error) {
handleError(error, $t('unable_to_hide_person'));
handleError(error, $t('errors.unable_to_hide_person'));
}
};
@ -236,7 +236,7 @@
}
await goto(`${AppRoute.PEOPLE}/${personToBeMergedIn.id}`, { replaceState: true });
} catch (error) {
handleError(error, $t('unable_to_save_name'));
handleError(error, $t('errors.unable_to_save_name'));
}
};
@ -262,7 +262,7 @@
type: NotificationType.Info,
});
} catch (error) {
handleError(error, $t('unable_to_save_name'));
handleError(error, $t('errors.unable_to_save_name'));
}
};

View file

@ -40,7 +40,7 @@
type: NotificationType.Info,
});
} catch (error) {
handleError(error, $t('unable_to_resolve_duplicate'));
handleError(error, $t('errors.unable_to_resolve_duplicate'));
}
};
</script>

View file

@ -125,7 +125,7 @@
type: NotificationType.Info,
});
} catch (error) {
handleError(error, $t('unable_to_create_library'));
handleError(error, $t('errors.unable_to_create_library'));
} finally {
toCreateLibrary = false;
await readLibraryList();
@ -143,7 +143,7 @@
closeAll();
await readLibraryList();
} catch (error) {
handleError(error, $t('unable_to_update_library'));
handleError(error, $t('errors.unable_to_update_library'));
}
};
@ -163,7 +163,7 @@
type: NotificationType.Info,
});
} catch (error) {
handleError(error, $t('unable_to_remove_library'));
handleError(error, $t('errors.unable_to_remove_library'));
} finally {
confirmDeleteLibrary = null;
deletedLibrary = null;
@ -181,7 +181,7 @@
type: NotificationType.Info,
});
} catch (error) {
handleError(error, $t('unable_to_scan_libraries'));
handleError(error, $t('errors.unable_to_scan_libraries'));
}
};
@ -193,7 +193,7 @@
type: NotificationType.Info,
});
} catch (error) {
handleError(error, $t('unable_to_scan_library'));
handleError(error, $t('errors.unable_to_scan_library'));
}
};
@ -205,7 +205,7 @@
type: NotificationType.Info,
});
} catch (error) {
handleError(error, $t('unable_to_scan_library'));
handleError(error, $t('errors.unable_to_scan_library'));
}
};
@ -217,7 +217,7 @@
type: NotificationType.Info,
});
} catch (error) {
handleError(error, $t('unable_to_scan_library'));
handleError(error, $t('errors.unable_to_scan_library'));
}
};

View file

@ -85,7 +85,7 @@
matches = [];
} catch (error) {
handleError(error, $t('unable_to_repair_items'));
handleError(error, $t('errors.unable_to_repair_items'));
} finally {
repairing = false;
}
@ -110,7 +110,7 @@
notificationController.show({ message: $t('refreshed'), type: NotificationType.Info });
} catch (error) {
handleError(error, $t('unable_to_load_items'));
handleError(error, $t('errors.unable_to_load_items'));
}
};
@ -121,7 +121,7 @@
notificationController.show({ message: `Matched 1 item`, type: NotificationType.Info });
}
} catch (error) {
handleError(error, $t('unable_to_check_item'));
handleError(error, $t('errors.unable_to_check_item'));
}
};
@ -137,7 +137,7 @@
count += await loadAndMatch(filenames.slice(index, index + chunkSize));
}
} catch (error) {
handleError(error, $t('unable_to_check_items'));
handleError(error, $t('errors.unable_to_check_items'));
} finally {
checking = false;
}