From c402d6f4b955bb1ba3d815d41486ae4aadd2c912 Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Fri, 20 Jan 2023 15:32:10 +0100 Subject: [PATCH 01/21] feat: portfolio reencrypt --- core/src/crypto.rs | 13 ++++++ core/src/database/mutation/candidate.rs | 2 +- core/src/database/mutation/parent.rs | 2 +- core/src/models/candidate_details.rs | 6 +-- core/src/services/application_service.rs | 50 +++++++++++++++++------- core/src/services/portfolio_service.rs | 36 +++++++++++++++-- 6 files changed, 86 insertions(+), 23 deletions(-) diff --git a/core/src/crypto.rs b/core/src/crypto.rs index 05e2644..1444f59 100644 --- a/core/src/crypto.rs +++ b/core/src/crypto.rs @@ -200,6 +200,19 @@ pub fn create_identity() -> (String, String) { ) } +pub async fn encrypt_buffer_with_recipients( + input_buffer: &[u8], + recipients: &Vec, +) -> Result, ServiceError> { + let mut output_buffer = vec![]; + age_encrypt_with_recipients(input_buffer, + &mut output_buffer, + &recipients.iter().map(|s| s.as_str()).collect() + ).await?; + + Ok(output_buffer) +} + async fn age_encrypt_with_recipients( input_buffer: &[u8], output_buffer: &mut W, diff --git a/core/src/database/mutation/candidate.rs b/core/src/database/mutation/candidate.rs index e5bbdc0..e8e723c 100644 --- a/core/src/database/mutation/candidate.rs +++ b/core/src/database/mutation/candidate.rs @@ -122,7 +122,7 @@ mod tests { let encrypted_details: EncryptedApplicationDetails = EncryptedApplicationDetails::new( &APPLICATION_DETAILS.lock().unwrap().clone(), - vec!["age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5".to_string()], + &vec!["age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5".to_string()], ).await.unwrap(); let candidate = Mutation::update_candidate_opt_details(&db, candidate, encrypted_details.candidate, 1).await.unwrap(); diff --git a/core/src/database/mutation/parent.rs b/core/src/database/mutation/parent.rs index 6959cb6..ee207d6 100644 --- a/core/src/database/mutation/parent.rs +++ b/core/src/database/mutation/parent.rs @@ -77,7 +77,7 @@ mod tests { let encrypted_details: EncryptedApplicationDetails = EncryptedApplicationDetails::new( &APPLICATION_DETAILS.lock().unwrap().clone(), - vec!["age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5".to_string()], + &vec!["age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5".to_string()], ) .await .unwrap(); diff --git a/core/src/models/candidate_details.rs b/core/src/models/candidate_details.rs index 836e903..3e2dcc4 100644 --- a/core/src/models/candidate_details.rs +++ b/core/src/models/candidate_details.rs @@ -321,7 +321,7 @@ impl From<&parent::Model> for EncryptedParentDetails { impl EncryptedApplicationDetails { pub async fn new( form: &ApplicationDetails, - recipients: Vec, + recipients: &Vec, ) -> Result { let candidate = EncryptedCandidateDetails::new(&form.candidate, &recipients).await?; let enc_parents = future::try_join_all( @@ -459,7 +459,7 @@ pub mod tests { async fn test_encrypted_application_details_new() { let encrypted_details = EncryptedApplicationDetails::new( &APPLICATION_DETAILS.lock().unwrap().clone(), - vec![PUBLIC_KEY.to_string()], + &vec![PUBLIC_KEY.to_string()], ) .await .unwrap(); @@ -488,7 +488,7 @@ pub mod tests { async fn test_encrypted_application_details_decrypt() { let encrypted_details = EncryptedApplicationDetails::new( &APPLICATION_DETAILS.lock().unwrap().clone(), - vec![PUBLIC_KEY.to_string()], + &vec![PUBLIC_KEY.to_string()], ) .await .unwrap(); diff --git a/core/src/services/application_service.rs b/core/src/services/application_service.rs index 991184c..8d8b959 100644 --- a/core/src/services/application_service.rs +++ b/core/src/services/application_service.rs @@ -265,8 +265,6 @@ impl ApplicationService { ).await }) ).await - - } async fn decrypt_private_key( @@ -291,7 +289,6 @@ impl ApplicationService { } } - // TODO pub async fn reset_password( admin_private_key: String, db: &DbConn, @@ -300,7 +297,6 @@ impl ApplicationService { let application = Query::find_application_by_id(db, id).await? .ok_or(ServiceError::CandidateNotFound)?; let candidate = ApplicationService::find_related_candidate(db, &application).await?; - let parents = Query::find_candidate_parents(db, &candidate).await?; let new_password_plain = crypto::random_12_char_string(); let new_password_hash = crypto::hash_password(new_password_plain.clone()).await?; @@ -319,6 +315,7 @@ impl ApplicationService { encrypted_priv_key ).await?; + // user might no have filled his details yet, but personal id number is filled from beginning let personal_id_number = EncryptedString::from(application.personal_id_number.clone()) .decrypt(&admin_private_key) @@ -330,8 +327,37 @@ impl ApplicationService { recipients.append(&mut admin_public_keys); recipients.append(&mut applications.iter().map(|a| a.public_key.to_owned()).collect()); + let candidate = Self::update_all_application_details(db, + application.id, + candidate, + &recipients, + &admin_private_key + ).await?; + + PortfolioService::reencrypt_portfolio( + candidate.id, + admin_private_key, + &recipients + ).await?; + + Ok( + CreateCandidateResponse { + application_id: id, + personal_id_number, + password: new_password_plain, + } + ) + } + + async fn update_all_application_details(db: &DbConn, + application_id: i32, + candidate: candidate::Model, + recipients: &Vec, + admin_private_key: &String + ) -> Result { + let parents = Query::find_candidate_parents(db, &candidate).await?; let dec_details = EncryptedApplicationDetails::from((&candidate, &parents)) - .decrypt(admin_private_key).await?; + .decrypt(admin_private_key.to_owned()).await?; let enc_details = EncryptedApplicationDetails::new(&dec_details, recipients).await?; @@ -341,23 +367,17 @@ impl ApplicationService { .ok_or(ServiceError::CandidateDetailsNotSet)?.to_string() ).await?; - Mutation::update_candidate_opt_details(db, + let candidate = Mutation::update_candidate_opt_details(db, candidate, enc_details.candidate, - application.id + application_id ).await?; for i in 0..enc_details.parents.len() { Mutation::add_parent_details(db, parents[i].clone(), enc_details.parents[i].clone()).await?; } - - Ok( - CreateCandidateResponse { - application_id: id, - personal_id_number, - password: new_password_plain, - } - ) + + Ok(candidate) } } diff --git a/core/src/services/portfolio_service.rs b/core/src/services/portfolio_service.rs index 19cede7..e05d0aa 100644 --- a/core/src/services/portfolio_service.rs +++ b/core/src/services/portfolio_service.rs @@ -368,15 +368,45 @@ impl PortfolioService { /// Returns decrypted portfolio zip as Vec of bytes pub async fn get_portfolio(candidate_id: i32, private_key: String) -> Result, ServiceError> { info!("PORTFOLIO {} DECRYPT STARTED", candidate_id); - let path = Self::get_file_store_path().join(&candidate_id.to_string()).to_path_buf(); - - let path = path.join(FileType::Age.as_str()); + let path = Self::get_file_store_path() + .join(&candidate_id.to_string()) + .join(FileType::Age.as_str()) + .to_path_buf(); let buffer = crypto::decrypt_file_with_private_key_as_buffer(path, &private_key).await?; info!("PORTFOLIO {} DECRYPT FINISHED", candidate_id); Ok(buffer) } + + pub async fn reencrypt_portfolio(candidate_id: i32, + private_key: String, + recipients: &Vec + ) -> Result<(), ServiceError> { + info!("PORTFOLIO {} REENCRYPT STARTED", candidate_id); + let path = Self::get_file_store_path() + .join(&candidate_id.to_string()) + .join(FileType::Age.as_str()) + .to_path_buf(); + + let plain_portfolio = crypto::decrypt_file_with_private_key_as_buffer( + path.to_owned(), + &private_key + ).await?; + + tokio::fs::remove_file(path.to_owned()).await?; + + let enc_portfolio= crypto::encrypt_buffer_with_recipients( + &plain_portfolio, + recipients + ).await?; + + tokio::fs::write(path, enc_portfolio).await?; + + info!("PORTFOLIO {} REENCRYPT FINISHED", candidate_id); + + Ok(()) + } } #[cfg(test)] From dd456a7870919ebcd6684906801e354da327b701 Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Fri, 20 Jan 2023 17:00:26 +0100 Subject: [PATCH 02/21] fix: password reset when portfolio not submitted --- core/src/services/application_service.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/core/src/services/application_service.rs b/core/src/services/application_service.rs index 8d8b959..1217fe7 100644 --- a/core/src/services/application_service.rs +++ b/core/src/services/application_service.rs @@ -6,7 +6,7 @@ use sea_orm::{DbConn, prelude::Uuid, IntoActiveModel}; use crate::{error::ServiceError, Query, utils::db::get_recipients, models::candidate_details::EncryptedApplicationDetails, models::{candidate::{ApplicationDetails, CreateCandidateResponse}, candidate_details::{EncryptedString, EncryptedCandidateDetails}, auth::AuthenticableTrait, application::ApplicationResponse}, Mutation, crypto::{hash_password, self}}; -use super::{parent_service::ParentService, candidate_service::CandidateService, session_service::SessionService, portfolio_service::PortfolioService}; +use super::{parent_service::ParentService, candidate_service::CandidateService, session_service::SessionService, portfolio_service::{PortfolioService, SubmissionProgress}}; const FIELD_OF_STUDY_PREFIXES: [&str; 3] = ["101", "102", "103"]; @@ -334,11 +334,13 @@ impl ApplicationService { &admin_private_key ).await?; - PortfolioService::reencrypt_portfolio( - candidate.id, - admin_private_key, - &recipients - ).await?; + if PortfolioService::get_submission_progress(candidate.id).await? == SubmissionProgress::Submitted { + PortfolioService::reencrypt_portfolio( + candidate.id, + admin_private_key, + &recipients + ).await?; + } Ok( CreateCandidateResponse { @@ -477,7 +479,6 @@ mod application_tests { assert!(!ApplicationService::is_application_id_valid(101)); } - // TODO #[tokio::test] async fn test_password_reset() { let db = get_memory_sqlite_connection().await; From 205996cc2e6fec0bb772125cf0524ecb57f4e570 Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Sat, 21 Jan 2023 23:28:35 +0100 Subject: [PATCH 03/21] refactor: remove portfolio file after encrypting --- core/src/services/portfolio_service.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/src/services/portfolio_service.rs b/core/src/services/portfolio_service.rs index e05d0aa..1091afb 100644 --- a/core/src/services/portfolio_service.rs +++ b/core/src/services/portfolio_service.rs @@ -394,13 +394,14 @@ impl PortfolioService { &private_key ).await?; - tokio::fs::remove_file(path.to_owned()).await?; - + let enc_portfolio= crypto::encrypt_buffer_with_recipients( &plain_portfolio, recipients ).await?; - + + tokio::fs::remove_file(path.to_owned()).await?; + tokio::fs::write(path, enc_portfolio).await?; info!("PORTFOLIO {} REENCRYPT FINISHED", candidate_id); From 783ed2baf7f0f77d078e06a280f84252c39cf2d2 Mon Sep 17 00:00:00 2001 From: EETagent Date: Fri, 20 Jan 2023 13:12:42 +0100 Subject: [PATCH 04/21] feat: init typesafe-i18n --- frontend/.typesafe-i18n.json | 7 +++++ frontend/package.json | 4 ++- frontend/pnpm-lock.yaml | 13 +++++++- frontend/src/translations/cs/index.ts | 8 +++++ frontend/src/translations/de/index.ts | 8 +++++ frontend/src/translations/formatters.ts | 11 +++++++ frontend/src/translations/i18n-svelte.ts | 12 +++++++ frontend/src/translations/i18n-types.ts | 19 +++++++++++ frontend/src/translations/i18n-util.async.ts | 25 +++++++++++++++ frontend/src/translations/i18n-util.sync.ts | 21 +++++++++++++ frontend/src/translations/i18n-util.ts | 33 ++++++++++++++++++++ 11 files changed, 159 insertions(+), 2 deletions(-) create mode 100644 frontend/.typesafe-i18n.json create mode 100644 frontend/src/translations/cs/index.ts create mode 100644 frontend/src/translations/de/index.ts create mode 100644 frontend/src/translations/formatters.ts create mode 100644 frontend/src/translations/i18n-svelte.ts create mode 100644 frontend/src/translations/i18n-types.ts create mode 100644 frontend/src/translations/i18n-util.async.ts create mode 100644 frontend/src/translations/i18n-util.sync.ts create mode 100644 frontend/src/translations/i18n-util.ts diff --git a/frontend/.typesafe-i18n.json b/frontend/.typesafe-i18n.json new file mode 100644 index 0000000..12eb8a1 --- /dev/null +++ b/frontend/.typesafe-i18n.json @@ -0,0 +1,7 @@ +{ + "baseLocale": "cs", + "adapter": "svelte", + "esmImports": true, + "outputPath": "./src/translations", + "$schema": "https://unpkg.com/typesafe-i18n@5.20.0/schema/typesafe-i18n.json" +} \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index 2c1e416..f10de62 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,7 +10,8 @@ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "lint": "prettier --plugin-search-dir . --check . && eslint .", - "format": "prettier --plugin-search-dir . --write ." + "format": "prettier --plugin-search-dir . --write .", + "typesafe-i18n": "typesafe-i18n" }, "devDependencies": { "@playwright/test": "^1.29.2", @@ -46,6 +47,7 @@ "svelte-tippy": "^1.3.2", "swiper": "^8.4.6", "tippy.js": "^6.3.7", + "typesafe-i18n": "^5.20.0", "yup": "^0.32.11" } } diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index d76650e..774c62b 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -34,6 +34,9 @@ dependencies: tippy.js: specifier: ^6.3.7 version: 6.3.7 + typesafe-i18n: + specifier: ^5.20.0 + version: 5.20.0(typescript@4.9.4) yup: specifier: ^0.32.11 version: 0.32.11 @@ -2385,11 +2388,19 @@ packages: engines: {node: '>=10'} dev: true + /typesafe-i18n@5.20.0(typescript@4.9.4): + resolution: {integrity: sha512-uOvKnVkp1tXRDNBz9Aom54qs0LP2xWrtDliMPdKm9Scsnvn0DC7ZqjSGdOWxVplpbFbqYWNZuzx5Q5jWOjnBTA==} + hasBin: true + peerDependencies: + typescript: '>=3.5.1' + dependencies: + typescript: 4.9.4 + dev: false + /typescript@4.9.4: resolution: {integrity: sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==} engines: {node: '>=4.2.0'} hasBin: true - dev: true /unconfig@0.2.2: resolution: {integrity: sha512-JN1MeYJ/POnjBj7NgOJJxPp6+NcD6Nd0hEuK0D89kjm9GvQQUq8HeE2Eb7PZgtu+64mWkDiqeJn1IZoLH7htPg==} diff --git a/frontend/src/translations/cs/index.ts b/frontend/src/translations/cs/index.ts new file mode 100644 index 0000000..71ee449 --- /dev/null +++ b/frontend/src/translations/cs/index.ts @@ -0,0 +1,8 @@ +import type { BaseTranslation } from '../i18n-types.js' + +const cs: BaseTranslation = { + // TODO: your translations go here + HI: 'Hi {name:string}! Please leave a star if you like this project: https://github.com/ivanhofer/typesafe-i18n', +} + +export default cs diff --git a/frontend/src/translations/de/index.ts b/frontend/src/translations/de/index.ts new file mode 100644 index 0000000..eaae244 --- /dev/null +++ b/frontend/src/translations/de/index.ts @@ -0,0 +1,8 @@ +import type { Translation } from '../i18n-types.js' + +const de: Translation = { + // this is an example Translation, just rename or delete this folder if you want + HI: 'Hallo {name}! Bitte hinterlasse einen Stern, wenn dir das Projekt gefällt: https://github.com/ivanhofer/typesafe-i18n', +} + +export default de diff --git a/frontend/src/translations/formatters.ts b/frontend/src/translations/formatters.ts new file mode 100644 index 0000000..9e0741e --- /dev/null +++ b/frontend/src/translations/formatters.ts @@ -0,0 +1,11 @@ +import type { FormattersInitializer } from 'typesafe-i18n' +import type { Locales, Formatters } from './i18n-types.js' + +export const initFormatters: FormattersInitializer = (locale: Locales) => { + + const formatters: Formatters = { + // add your formatter functions here + } + + return formatters +} diff --git a/frontend/src/translations/i18n-svelte.ts b/frontend/src/translations/i18n-svelte.ts new file mode 100644 index 0000000..23d478d --- /dev/null +++ b/frontend/src/translations/i18n-svelte.ts @@ -0,0 +1,12 @@ +// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten. +/* eslint-disable */ + +import { initI18nSvelte } from 'typesafe-i18n/svelte' +import type { Formatters, Locales, TranslationFunctions, Translations } from './i18n-types.js' +import { loadedFormatters, loadedLocales } from './i18n-util.js' + +const { locale, LL, setLocale } = initI18nSvelte(loadedLocales, loadedFormatters) + +export { locale, LL, setLocale } + +export default LL diff --git a/frontend/src/translations/i18n-types.ts b/frontend/src/translations/i18n-types.ts new file mode 100644 index 0000000..9ae0378 --- /dev/null +++ b/frontend/src/translations/i18n-types.ts @@ -0,0 +1,19 @@ +// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten. +/* eslint-disable */ +import type { BaseTranslation as BaseTranslationType } from 'typesafe-i18n' + +export type BaseTranslation = BaseTranslationType +export type BaseLocale = 'cs' + +export type Locales = + | 'cs' + +export type Translation = RootTranslation + +export type Translations = RootTranslation + +type RootTranslation = {} + +export type TranslationFunctions = {} + +export type Formatters = {} diff --git a/frontend/src/translations/i18n-util.async.ts b/frontend/src/translations/i18n-util.async.ts new file mode 100644 index 0000000..5d4505a --- /dev/null +++ b/frontend/src/translations/i18n-util.async.ts @@ -0,0 +1,25 @@ +// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten. +/* eslint-disable */ + +import { initFormatters } from './formatters.js' +import type { Locales, Translations } from './i18n-types.js' +import { loadedFormatters, loadedLocales, locales } from './i18n-util.js' + +const localeTranslationLoaders = { +} + +const updateDictionary = (locale: Locales, dictionary: Partial): Translations => + loadedLocales[locale] = { ...loadedLocales[locale], ...dictionary } + +export const importLocaleAsync = async (locale: Locales): Promise => + (await localeTranslationLoaders[locale]()).default as unknown as Translations + +export const loadLocaleAsync = async (locale: Locales): Promise => { + updateDictionary(locale, await importLocaleAsync(locale)) + loadFormatters(locale) +} + +export const loadAllLocalesAsync = (): Promise => Promise.all(locales.map(loadLocaleAsync)) + +export const loadFormatters = (locale: Locales): void => + void (loadedFormatters[locale] = initFormatters(locale)) diff --git a/frontend/src/translations/i18n-util.sync.ts b/frontend/src/translations/i18n-util.sync.ts new file mode 100644 index 0000000..523c1eb --- /dev/null +++ b/frontend/src/translations/i18n-util.sync.ts @@ -0,0 +1,21 @@ +// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten. +/* eslint-disable */ + +import { initFormatters } from './formatters.js' +import type { Locales, Translations } from './i18n-types.js' +import { loadedFormatters, loadedLocales, locales } from './i18n-util.js' + +const localeTranslations = { +} + +export const loadLocale = (locale: Locales): void => { + if (loadedLocales[locale]) return + + loadedLocales[locale] = localeTranslations[locale] as unknown as Translations + loadFormatters(locale) +} + +export const loadAllLocales = (): void => locales.forEach(loadLocale) + +export const loadFormatters = (locale: Locales): void => + void (loadedFormatters[locale] = initFormatters(locale)) diff --git a/frontend/src/translations/i18n-util.ts b/frontend/src/translations/i18n-util.ts new file mode 100644 index 0000000..109c3be --- /dev/null +++ b/frontend/src/translations/i18n-util.ts @@ -0,0 +1,33 @@ +// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten. +/* eslint-disable */ + +import { i18n as initI18n, i18nObject as initI18nObject, i18nString as initI18nString } from 'typesafe-i18n' +import type { LocaleDetector } from 'typesafe-i18n/detectors' +import type { LocaleTranslationFunctions, TranslateByString } from 'typesafe-i18n' +import { detectLocale as detectLocaleFn } from 'typesafe-i18n/detectors' +import type { Formatters, Locales, Translations, TranslationFunctions } from './i18n-types.js' + +export const baseLocale: Locales = 'cs' + +export const locales: Locales[] = [ +] + +export const isLocale = (locale: string): locale is Locales => locales.includes(locale as Locales) + +export const loadedLocales: Record = {} as Record + +export const loadedFormatters: Record = {} as Record + +export const i18nString = (locale: Locales): TranslateByString => initI18nString(locale, loadedFormatters[locale]) + +export const i18nObject = (locale: Locales): TranslationFunctions => + initI18nObject( + locale, + loadedLocales[locale], + loadedFormatters[locale] + ) + +export const i18n = (): LocaleTranslationFunctions => + initI18n(loadedLocales, loadedFormatters) + +export const detectLocale = (...detectors: LocaleDetector[]): Locales => detectLocaleFn(baseLocale, locales, ...detectors) From e83805743a5daa8c41a0e44a4282d6e9eb8b3d89 Mon Sep 17 00:00:00 2001 From: EETagent Date: Fri, 20 Jan 2023 13:12:56 +0100 Subject: [PATCH 05/21] chore: add VSCode i18n ally settings --- .../.vscode/i18n-ally-custom-framework.yml | 18 ++++++++++++++++++ frontend/.vscode/settings.json | 6 ++++++ 2 files changed, 24 insertions(+) create mode 100644 frontend/.vscode/i18n-ally-custom-framework.yml create mode 100644 frontend/.vscode/settings.json diff --git a/frontend/.vscode/i18n-ally-custom-framework.yml b/frontend/.vscode/i18n-ally-custom-framework.yml new file mode 100644 index 0000000..c17d03b --- /dev/null +++ b/frontend/.vscode/i18n-ally-custom-framework.yml @@ -0,0 +1,18 @@ +languageIds: + - typescript + - javascript + - typescriptreact + - javascriptreact + - svelte + - html + +usageMatchRegex: + - "\\$?LL\\.({key})\\(((\\{.*\\})|([^)]*))\\)" + +refactorTemplates: + - '{$LL.$1()}' + - '{LL.$1()}' + - '$LL.$1()' + - 'LL.$1()' + +monopoly: true diff --git a/frontend/.vscode/settings.json b/frontend/.vscode/settings.json new file mode 100644 index 0000000..c7be7fc --- /dev/null +++ b/frontend/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "i18n-ally.pathMatcher": "{locale}/index.{ext}", + "i18n-ally.enabledParsers": ["ts", "js"], + "i18n-ally.keystyle": "nested", + "i18n-ally.localesPaths": ["src/translations"] +} From 474caab0e1e3df4a199ad539625940ff8c358e38 Mon Sep 17 00:00:00 2001 From: EETagent Date: Fri, 20 Jan 2023 13:19:11 +0100 Subject: [PATCH 06/21] =?UTF-8?q?feat:=20deportace=20N=C4=9Bmc=C5=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/translations/cs/index.ts | 2 -- frontend/src/translations/de/index.ts | 8 -------- frontend/src/translations/i18n-util.async.ts | 1 + frontend/src/translations/i18n-util.sync.ts | 3 +++ frontend/src/translations/i18n-util.ts | 1 + 5 files changed, 5 insertions(+), 10 deletions(-) delete mode 100644 frontend/src/translations/de/index.ts diff --git a/frontend/src/translations/cs/index.ts b/frontend/src/translations/cs/index.ts index 71ee449..7c0994b 100644 --- a/frontend/src/translations/cs/index.ts +++ b/frontend/src/translations/cs/index.ts @@ -1,8 +1,6 @@ import type { BaseTranslation } from '../i18n-types.js' const cs: BaseTranslation = { - // TODO: your translations go here - HI: 'Hi {name:string}! Please leave a star if you like this project: https://github.com/ivanhofer/typesafe-i18n', } export default cs diff --git a/frontend/src/translations/de/index.ts b/frontend/src/translations/de/index.ts deleted file mode 100644 index eaae244..0000000 --- a/frontend/src/translations/de/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { Translation } from '../i18n-types.js' - -const de: Translation = { - // this is an example Translation, just rename or delete this folder if you want - HI: 'Hallo {name}! Bitte hinterlasse einen Stern, wenn dir das Projekt gefällt: https://github.com/ivanhofer/typesafe-i18n', -} - -export default de diff --git a/frontend/src/translations/i18n-util.async.ts b/frontend/src/translations/i18n-util.async.ts index 5d4505a..e9e06f8 100644 --- a/frontend/src/translations/i18n-util.async.ts +++ b/frontend/src/translations/i18n-util.async.ts @@ -6,6 +6,7 @@ import type { Locales, Translations } from './i18n-types.js' import { loadedFormatters, loadedLocales, locales } from './i18n-util.js' const localeTranslationLoaders = { + cs: () => import('./cs/index.js'), } const updateDictionary = (locale: Locales, dictionary: Partial): Translations => diff --git a/frontend/src/translations/i18n-util.sync.ts b/frontend/src/translations/i18n-util.sync.ts index 523c1eb..5ad0a1d 100644 --- a/frontend/src/translations/i18n-util.sync.ts +++ b/frontend/src/translations/i18n-util.sync.ts @@ -5,7 +5,10 @@ import { initFormatters } from './formatters.js' import type { Locales, Translations } from './i18n-types.js' import { loadedFormatters, loadedLocales, locales } from './i18n-util.js' +import cs from './cs/index.js' + const localeTranslations = { + cs, } export const loadLocale = (locale: Locales): void => { diff --git a/frontend/src/translations/i18n-util.ts b/frontend/src/translations/i18n-util.ts index 109c3be..bbd277a 100644 --- a/frontend/src/translations/i18n-util.ts +++ b/frontend/src/translations/i18n-util.ts @@ -10,6 +10,7 @@ import type { Formatters, Locales, Translations, TranslationFunctions } from './ export const baseLocale: Locales = 'cs' export const locales: Locales[] = [ + 'cs' ] export const isLocale = (locale: string): locale is Locales => locales.includes(locale as Locales) From 02c2953b64b87f10e8b957152143fc9c161c680b Mon Sep 17 00:00:00 2001 From: EETagent Date: Fri, 20 Jan 2023 13:23:35 +0100 Subject: [PATCH 07/21] feat: aliases for paths --- frontend/svelte.config.js | 7 ++++++- frontend/tsconfig.json | 9 ++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/frontend/svelte.config.js b/frontend/svelte.config.js index 2ef33af..a3f4721 100644 --- a/frontend/svelte.config.js +++ b/frontend/svelte.config.js @@ -1,5 +1,6 @@ import adapter from '@sveltejs/adapter-node'; import preprocess from 'svelte-preprocess'; +import path from "path"; import { windi } from 'svelte-windicss-preprocess'; /** @type {import('@sveltejs/kit').Config} */ @@ -8,7 +9,11 @@ const config = { // for more information about preprocessors preprocess: [preprocess(), windi({})], kit: { - adapter: adapter({ out: 'build' }) + adapter: adapter({ out: 'build' }), + alias: { + $i18n: path.resolve('./src/translations'), + } + } }; diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 8793475..7176a96 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -9,6 +9,13 @@ "resolveJsonModule": true, "skipLibCheck": true, "sourceMap": true, - "strict": true + "strict": true, + "paths": { + "$lib": ["src/lib"], + "$lib/*": ["src/lib/*"], + "$i18n": ["src/translations"], + "$i18n/*": ["src/translations/*"], + "$params": ["src/params"], + } } } From b658532f1fe906535da2b59f6d4ea08598b60956 Mon Sep 17 00:00:00 2001 From: EETagent Date: Fri, 20 Jan 2023 14:13:54 +0100 Subject: [PATCH 08/21] chore: remove broken config overrides --- .../.vscode/i18n-ally-custom-framework.yml | 18 ------------------ frontend/.vscode/settings.json | 6 ------ 2 files changed, 24 deletions(-) delete mode 100644 frontend/.vscode/i18n-ally-custom-framework.yml delete mode 100644 frontend/.vscode/settings.json diff --git a/frontend/.vscode/i18n-ally-custom-framework.yml b/frontend/.vscode/i18n-ally-custom-framework.yml deleted file mode 100644 index c17d03b..0000000 --- a/frontend/.vscode/i18n-ally-custom-framework.yml +++ /dev/null @@ -1,18 +0,0 @@ -languageIds: - - typescript - - javascript - - typescriptreact - - javascriptreact - - svelte - - html - -usageMatchRegex: - - "\\$?LL\\.({key})\\(((\\{.*\\})|([^)]*))\\)" - -refactorTemplates: - - '{$LL.$1()}' - - '{LL.$1()}' - - '$LL.$1()' - - 'LL.$1()' - -monopoly: true diff --git a/frontend/.vscode/settings.json b/frontend/.vscode/settings.json deleted file mode 100644 index c7be7fc..0000000 --- a/frontend/.vscode/settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "i18n-ally.pathMatcher": "{locale}/index.{ext}", - "i18n-ally.enabledParsers": ["ts", "js"], - "i18n-ally.keystyle": "nested", - "i18n-ally.localesPaths": ["src/translations"] -} From 14c334bb5570af50cb4a1462accecb90f79aa700 Mon Sep 17 00:00:00 2001 From: EETagent Date: Fri, 20 Jan 2023 14:14:07 +0100 Subject: [PATCH 09/21] chore: fix tsconfig --- frontend/tsconfig.json | 7 ------- 1 file changed, 7 deletions(-) diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 7176a96..ab896ad 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -10,12 +10,5 @@ "skipLibCheck": true, "sourceMap": true, "strict": true, - "paths": { - "$lib": ["src/lib"], - "$lib/*": ["src/lib/*"], - "$i18n": ["src/translations"], - "$i18n/*": ["src/translations/*"], - "$params": ["src/params"], - } } } From cbb1a9a29e2bad486ce229e842afe9fe8030a604 Mon Sep 17 00:00:00 2001 From: EETagent Date: Fri, 20 Jan 2023 14:14:19 +0100 Subject: [PATCH 10/21] feat? initial translation --- .../(candidate)/auth/login/+page.svelte | 6 +-- frontend/src/translations/cs/index.ts | 15 ++++++-- frontend/src/translations/i18n-types.ts | 38 +++++++++++++++++-- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/frontend/src/routes/(candidate)/auth/login/+page.svelte b/frontend/src/routes/(candidate)/auth/login/+page.svelte index cff8cc5..3f1bd4c 100644 --- a/frontend/src/routes/(candidate)/auth/login/+page.svelte +++ b/frontend/src/routes/(candidate)/auth/login/+page.svelte @@ -1,4 +1,5 @@ @@ -431,10 +432,9 @@