From b0346e08f45c6739da22f370b657a41cf2a9cd67 Mon Sep 17 00:00:00 2001 From: Kashif Date: Mon, 12 Aug 2024 13:12:54 +0530 Subject: [PATCH] feat(payout_link): add localisation support for payout link's templates (#5552) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- .typos.toml | 15 ++ Cargo.lock | 134 ++++++++++++++++-- crates/api_models/src/payouts.rs | 1 + crates/common_utils/src/consts.rs | 3 + crates/hyperswitch_domain_models/src/api.rs | 1 + crates/router/Cargo.toml | 2 +- crates/router/locales/ar.yml | 42 ++++++ crates/router/locales/ca.yml | 42 ++++++ crates/router/locales/de.yml | 42 ++++++ crates/router/locales/en-GB.yml | 42 ++++++ crates/router/locales/en.yml | 42 ++++++ crates/router/locales/es.yml | 42 ++++++ crates/router/locales/fr-BE.yml | 42 ++++++ crates/router/locales/fr.yml | 42 ++++++ crates/router/locales/he.yml | 42 ++++++ crates/router/locales/it.yml | 42 ++++++ crates/router/locales/ja.yml | 42 ++++++ crates/router/locales/nl.yml | 42 ++++++ crates/router/locales/pl.yml | 42 ++++++ crates/router/locales/pt.yml | 42 ++++++ crates/router/locales/ru.yml | 42 ++++++ crates/router/locales/sv.yml | 42 ++++++ crates/router/locales/zh.yml | 42 ++++++ crates/router/src/compatibility/wrap.rs | 1 + .../payout_link/initiate/index.html | 2 +- .../payout_link/initiate/script.js | 30 ++-- .../payout_link/status/index.html | 2 +- .../generic_link/payout_link/status/script.js | 26 ++-- crates/router/src/core/payment_link.rs | 6 +- crates/router/src/core/payment_methods.rs | 7 +- crates/router/src/core/payout_link.rs | 5 + crates/router/src/core/payouts.rs | 10 +- crates/router/src/lib.rs | 4 + crates/router/src/locale.rs | 3 + crates/router/src/routes.rs | 1 + crates/router/src/routes/payout_link.rs | 26 +++- crates/router/src/routes/payouts.rs | 15 +- crates/router/src/services/api.rs | 5 +- .../src/services/api/generic_link_response.rs | 68 +++++---- .../api/generic_link_response/context.rs | 80 +++++++++++ 40 files changed, 1077 insertions(+), 84 deletions(-) create mode 100644 crates/router/locales/ar.yml create mode 100644 crates/router/locales/ca.yml create mode 100644 crates/router/locales/de.yml create mode 100644 crates/router/locales/en-GB.yml create mode 100644 crates/router/locales/en.yml create mode 100644 crates/router/locales/es.yml create mode 100644 crates/router/locales/fr-BE.yml create mode 100644 crates/router/locales/fr.yml create mode 100644 crates/router/locales/he.yml create mode 100644 crates/router/locales/it.yml create mode 100644 crates/router/locales/ja.yml create mode 100644 crates/router/locales/nl.yml create mode 100644 crates/router/locales/pl.yml create mode 100644 crates/router/locales/pt.yml create mode 100644 crates/router/locales/ru.yml create mode 100644 crates/router/locales/sv.yml create mode 100644 crates/router/locales/zh.yml create mode 100644 crates/router/src/locale.rs create mode 100644 crates/router/src/services/api/generic_link_response/context.rs diff --git a/.typos.toml b/.typos.toml index 82fb84ecf3..2f68e039cd 100644 --- a/.typos.toml +++ b/.typos.toml @@ -62,5 +62,20 @@ extend-exclude = [ "openapi/open_api_spec.yaml", # no longer updated "crates/router/src/utils/user/blocker_emails.txt", # this file contains various email domains "CHANGELOG.md", # This file contains all the commits + "crates/router/locales/ar.yml", # locales + "crates/router/locales/ca.yml", # locales + "crates/router/locales/de.yml", # locales + "crates/router/locales/es.yml", # locales + "crates/router/locales/fr-BE.yml", # locales + "crates/router/locales/fr.yml", # locales + "crates/router/locales/he.yml", # locales + "crates/router/locales/it.yml", # locales + "crates/router/locales/ja.yml", # locales + "crates/router/locales/nl.yml", # locales + "crates/router/locales/pl.yml", # locales + "crates/router/locales/pt.yml", # locales + "crates/router/locales/ru.yml", # locales + "crates/router/locales/sv.yml", # locales + "crates/router/locales/zh.yml", # locales "crates/router/src/core/payment_link/locale.js" # this file contains converision of static strings in various languages ] diff --git a/Cargo.lock b/Cargo.lock index 9d37e75077..c0ff88bfcf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1488,6 +1488,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa" +[[package]] +name = "base62" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f879ef8fc74665ed7f0e6127cb106315888fc2744f68e14b74f83edbb2a08992" + [[package]] name = "base64" version = "0.13.1" @@ -4321,6 +4327,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "libyml" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64804cc6a5042d4f05379909ba25b503ec04e2c082151d62122d5dcaa274b961" + [[package]] name = "libz-sys" version = "1.1.16" @@ -4383,9 +4395,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru-cache" @@ -4474,9 +4486,9 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memoffset" @@ -4693,6 +4705,15 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "normpath" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec60c60a693226186f5d6edf073232bfb6464ed97eb22cf3b01c1e8198fd97f5" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -5323,7 +5344,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" dependencies = [ - "siphasher", + "siphasher 0.3.11", ] [[package]] @@ -6126,6 +6147,7 @@ dependencies = [ "router_derive", "router_env", "roxmltree", + "rust-i18n", "rust_decimal", "rustc-hash", "rustls 0.22.4", @@ -6229,6 +6251,57 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rust-i18n" +version = "3.1.1" +source = "git+https://github.com/kashif-m/rust-i18n?rev=f2d8096aaaff7a87a847c35a5394c269f75e077a#f2d8096aaaff7a87a847c35a5394c269f75e077a" +dependencies = [ + "globwalk", + "once_cell", + "regex", + "rust-i18n-macro", + "rust-i18n-support", + "smallvec 1.13.2", +] + +[[package]] +name = "rust-i18n-macro" +version = "3.1.1" +source = "git+https://github.com/kashif-m/rust-i18n?rev=f2d8096aaaff7a87a847c35a5394c269f75e077a#f2d8096aaaff7a87a847c35a5394c269f75e077a" +dependencies = [ + "glob", + "once_cell", + "proc-macro2", + "quote", + "rust-i18n-support", + "serde", + "serde_json", + "serde_yml", + "syn 2.0.57", +] + +[[package]] +name = "rust-i18n-support" +version = "3.1.1" +source = "git+https://github.com/kashif-m/rust-i18n?rev=f2d8096aaaff7a87a847c35a5394c269f75e077a#f2d8096aaaff7a87a847c35a5394c269f75e077a" +dependencies = [ + "arc-swap", + "base62", + "globwalk", + "itertools 0.11.0", + "lazy_static", + "normpath", + "once_cell", + "proc-macro2", + "regex", + "serde", + "serde_json", + "serde_yml", + "siphasher 1.0.1", + "toml 0.7.8", + "triomphe", +] + [[package]] name = "rust-ini" version = "0.19.0" @@ -6465,9 +6538,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -6607,9 +6680,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.205" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "e33aedb1a7135da52b7c21791455563facbbcc43d0f0f66165b42c21b3dfb150" dependencies = [ "serde_derive", ] @@ -6648,9 +6721,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.205" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "692d6f5ac90220161d6774db30c662202721e64aed9058d2c394f451261420c1" dependencies = [ "proc-macro2", "quote", @@ -6659,12 +6732,13 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.115" +version = "1.0.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" dependencies = [ "indexmap 2.3.0", "itoa", + "memchr", "ryu", "serde", ] @@ -6761,6 +6835,23 @@ dependencies = [ "syn 2.0.57", ] +[[package]] +name = "serde_yml" +version = "0.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e76bab63c3fd98d27c17f9cbce177f64a91f5e69ac04cafe04e1bb25d1dc3c" +dependencies = [ + "indexmap 2.3.0", + "itoa", + "libyml", + "log", + "memchr", + "ryu", + "serde", + "serde_json", + "tempfile", +] + [[package]] name = "serial_test" version = "3.0.0" @@ -6888,6 +6979,12 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "skeptic" version = "0.13.7" @@ -7189,6 +7286,12 @@ dependencies = [ "urlencoding", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "storage_impl" version = "0.1.0" @@ -8231,6 +8334,11 @@ name = "triomphe" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" +dependencies = [ + "arc-swap", + "serde", + "stable_deref_trait", +] [[package]] name = "try-lock" diff --git a/crates/api_models/src/payouts.rs b/crates/api_models/src/payouts.rs index 3333fb6f54..b90b34cdff 100644 --- a/crates/api_models/src/payouts.rs +++ b/crates/api_models/src/payouts.rs @@ -764,6 +764,7 @@ pub struct PayoutLinkDetails { pub enabled_payment_methods: Vec, pub amount: common_utils::types::StringMajorUnit, pub currency: common_enums::Currency, + pub locale: String, } #[derive(Clone, Debug, serde::Serialize)] diff --git a/crates/common_utils/src/consts.rs b/crates/common_utils/src/consts.rs index a331a05f6f..fd15596396 100644 --- a/crates/common_utils/src/consts.rs +++ b/crates/common_utils/src/consts.rs @@ -127,3 +127,6 @@ pub const WILDCARD_DOMAIN_REGEX: &str = r"^((\*|https?)?://)?((\*\.|[A-Za-z0-9][ /// Maximum allowed length for MerchantName pub const MAX_ALLOWED_MERCHANT_NAME_LENGTH: usize = 64; + +/// Default locale +pub const DEFAULT_LOCALE: &str = "en"; diff --git a/crates/hyperswitch_domain_models/src/api.rs b/crates/hyperswitch_domain_models/src/api.rs index b013d2b790..d8a4f998e1 100644 --- a/crates/hyperswitch_domain_models/src/api.rs +++ b/crates/hyperswitch_domain_models/src/api.rs @@ -64,6 +64,7 @@ pub struct PaymentLinkStatusData { pub struct GenericLinks { pub allowed_domains: HashSet, pub data: GenericLinksData, + pub locale: String, } #[derive(Debug, Eq, PartialEq)] diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml index 3e0470cc08..8040979abb 100644 --- a/crates/router/Cargo.toml +++ b/crates/router/Cargo.toml @@ -97,6 +97,7 @@ reqwest = { version = "0.11.27", features = ["json", "native-tls", "__rustls", " ring = "0.17.8" roxmltree = "0.19.0" rust_decimal = { version = "1.35.0", features = ["serde-with-float", "serde-with-str"] } +rust-i18n = { git = "https://github.com/kashif-m/rust-i18n", rev = "f2d8096aaaff7a87a847c35a5394c269f75e077a" } rustc-hash = "1.1.0" rustls = "0.22" rustls-pemfile = "2" @@ -161,7 +162,6 @@ time = { version = "0.3.35", features = ["macros"] } tokio = "1.37.0" wiremock = "0.6.0" - # First party dev-dependencies test_utils = { version = "0.1.0", path = "../test_utils" } diff --git a/crates/router/locales/ar.yml b/crates/router/locales/ar.yml new file mode 100644 index 0000000000..5cc89daa47 --- /dev/null +++ b/crates/router/locales/ar.yml @@ -0,0 +1,42 @@ +_version: 1 + +payout_link: + initiate: + not_allowed: "لا يُسمح لك بمشاهدة هذا المحتوى" + title: "روابط الدفع" + status: + title: "حالة الدفع" + info: + ref_id: "معرف المرجع" + error_code: "رمز الخطأ" + error_message: "رسالة الخطأ" + message: + failed: "فشل في معالجة الدفع الخاص بك. يرجى التحقق مع مزود الخدمة للحصول على مزيد من التفاصيل." + processing: "يجب معالجة الدفع الخاص بك خلال 2-3 أيام عمل." + success: "تم تنفيذ الدفع إلى طريقة الدفع المختارة." + redirection_text: + redirecting: "جارٍ إعادة التوجيه..." + redirecting_in: "إعادة التوجيه خلال" + seconds: "ثوانٍ..." + text: + failed: "فشل الدفع" + processing: "الدفع قيد المعالجة" + success: "الدفع ناجح" + +time: + am: "صباحا" + pm: "مساء" + +months: + january: "يناير" + february: "فبراير" + march: "مارس" + april: "أبريل" + may: "مايو" + june: "يونيو" + july: "يوليو" + august: "أغسطس" + september: "سبتمبر" + october: "أكتوبر" + november: "نوفمبر" + december: "ديسمبر" diff --git a/crates/router/locales/ca.yml b/crates/router/locales/ca.yml new file mode 100644 index 0000000000..df4d40bb20 --- /dev/null +++ b/crates/router/locales/ca.yml @@ -0,0 +1,42 @@ +_version: 1 + +payout_link: + initiate: + not_allowed: "No tens permís per veure aquest contingut" + title: "Enllaços de Pagament" + status: + title: "Estat del Pagament" + info: + ref_id: "ID de Referència" + error_code: "Codi d'Error" + error_message: "Missatge d'Error" + message: + failed: "No s'ha pogut processar el teu pagament. Si us plau, comprova-ho amb el teu proveïdor per obtenir més detalls." + processing: "El teu pagament hauria de ser processat en 2-3 dies hàbils." + success: "El teu pagament s'ha realitzat al mètode de pagament seleccionat." + redirection_text: + redirecting: "Redirigint..." + redirecting_in: "Redirigint en" + seconds: "segons..." + text: + failed: "Falla en el Pagament" + processing: "Pagament en Procés" + success: "Pagament Exitos" + +time: + am: "AM" + pm: "PM" + +months: + january: "Gener" + february: "Febrer" + march: "Març" + april: "Abril" + may: "Maig" + june: "Juny" + july: "Juliol" + august: "Agost" + september: "Setembre" + october: "Octubre" + november: "Novembre" + december: "Desembre" diff --git a/crates/router/locales/de.yml b/crates/router/locales/de.yml new file mode 100644 index 0000000000..4a2ac4c4ea --- /dev/null +++ b/crates/router/locales/de.yml @@ -0,0 +1,42 @@ +_version: 1 + +payout_link: + initiate: + not_allowed: "Sie dürfen diesen Inhalt nicht anzeigen" + title: "Auszahlungslinks" + status: + title: "Auszahlungsstatus" + info: + ref_id: "Referenz-ID" + error_code: "Fehlercode" + error_message: "Fehlermeldung" + message: + failed: "Die Auszahlung konnte nicht verarbeitet werden. Bitte überprüfen Sie weitere Details bei Ihrem Anbieter." + processing: "Ihre Auszahlung sollte innerhalb von 2-3 Werktagen verarbeitet werden." + success: "Ihre Auszahlung wurde auf die ausgewählte Zahlungsmethode vorgenommen." + redirection_text: + redirecting: "Weiterleitung..." + redirecting_in: "Weiterleitung in" + seconds: "Sekunden..." + text: + failed: "Auszahlung fehlgeschlagen" + processing: "Auszahlung wird bearbeitet" + success: "Auszahlung erfolgreich" + +time: + am: "AM" + pm: "PM" + +months: + january: "Januar" + february: "Februar" + march: "März" + april: "April" + may: "Mai" + june: "Juni" + july: "Juli" + august: "August" + september: "September" + october: "Oktober" + november: "November" + december: "Dezember" diff --git a/crates/router/locales/en-GB.yml b/crates/router/locales/en-GB.yml new file mode 100644 index 0000000000..5d0cdca4f0 --- /dev/null +++ b/crates/router/locales/en-GB.yml @@ -0,0 +1,42 @@ +_version: 1 + +payout_link: + initiate: + not_allowed: "You are not allowed to view this content" + title: "Payout Links" + status: + title: "Payout Status" + info: + ref_id: "Ref Id" + error_code: "Error Code" + error_message: "Error Message" + message: + failed: "Failed to process your payout. Please check with your provider for more details." + processing: "Your payout should be processed within 2-3 business days." + success: "Your payout was made to selected payment method." + redirection_text: + redirecting: "Redirecting..." + redirecting_in: "Redirecting in" + seconds: "seconds..." + text: + failed: "Payout Failed" + processing: "Payout Processing" + success: "Payout Successful" + +time: + am: "AM" + pm: "PM" + +months: + january: "January" + february: "February" + march: "March" + april: "April" + may: "May" + june: "June" + july: "July" + august: "August" + september: "September" + october: "October" + november: "November" + december: "December" diff --git a/crates/router/locales/en.yml b/crates/router/locales/en.yml new file mode 100644 index 0000000000..c85be7ccf4 --- /dev/null +++ b/crates/router/locales/en.yml @@ -0,0 +1,42 @@ +_version: 1 + +payout_link: + initiate: + not_allowed: "You are not allowed to view this content" + title: "Payout Links" + status: + title: "Payout Status" + info: + ref_id: "Ref Id" + error_code: "Error Code" + error_message: "Error Message" + message: + failed: "Failed to process your payout. Please check with your provider for more details." + processing: "Your payout should be processed within 2-3 business days." + success: "Your payout was made to selected payment method." + redirection_text: + redirecting: "Redirecting ..." + redirecting_in: "Redirecting in" + seconds: "seconds ..." + text: + failed: "Payout Failed" + processing: "Payout Processing" + success: "Payout Successful" + +time: + am: "AM" + pm: "PM" + +months: + january: "January" + february: "February" + march: "March" + april: "April" + may: "May" + june: "June" + july: "July" + august: "August" + september: "September" + october: "October" + november: "November" + december: "December" \ No newline at end of file diff --git a/crates/router/locales/es.yml b/crates/router/locales/es.yml new file mode 100644 index 0000000000..ebe296d067 --- /dev/null +++ b/crates/router/locales/es.yml @@ -0,0 +1,42 @@ +_version: 1 + +payout_link: + initiate: + not_allowed: "No tienes permiso para ver este contenido" + title: "Enlaces de Pago" + status: + title: "Estado del Pago" + info: + ref_id: "ID de Referencia" + error_code: "Código de Error" + error_message: "Mensaje de Error" + message: + failed: "No se pudo procesar tu pago. Consulta con tu proveedor para más detalles." + processing: "Tu pago debería ser procesado en 2-3 días hábiles." + success: "Tu pago se realizó al método de pago seleccionado." + redirection_text: + redirecting: "Redirigiendo..." + redirecting_in: "Redirigiendo en" + seconds: "segundos..." + text: + failed: "Fallo en el Pago" + processing: "Pago en Proceso" + success: "Pago Exitoso" + +time: + am: "AM" + pm: "PM" + +months: + january: "Enero" + february: "Febrero" + march: "Marzo" + april: "Abril" + may: "Mayo" + june: "Junio" + july: "Julio" + august: "Agosto" + september: "Septiembre" + october: "Octubre" + november: "Noviembre" + december: "Diciembre" diff --git a/crates/router/locales/fr-BE.yml b/crates/router/locales/fr-BE.yml new file mode 100644 index 0000000000..5f5116ea92 --- /dev/null +++ b/crates/router/locales/fr-BE.yml @@ -0,0 +1,42 @@ +_version: 1 + +payout_link: + initiate: + not_allowed: "Vous n'êtes pas autorisé à voir ce contenu" + title: "Liens de paiement" + status: + title: "Statut du paiement" + info: + ref_id: "ID de référence" + error_code: "Code d'erreur" + error_message: "Message d'erreur" + message: + failed: "Échec du traitement de votre paiement. Veuillez vérifier auprès de votre fournisseur pour plus de détails." + processing: "Votre paiement devrait être traité dans les 2 à 3 jours ouvrables." + success: "Votre paiement a été effectué sur le mode de paiement sélectionné." + redirection_text: + redirecting: "Redirection..." + redirecting_in: "Redirection dans" + seconds: "secondes..." + text: + failed: "Échec du paiement" + processing: "Paiement en cours" + success: "Paiement réussi" + +time: + am: "AM" + pm: "PM" + +months: + january: "Janvier" + february: "Février" + march: "Mars" + april: "Avril" + may: "Mai" + june: "Juin" + july: "Juillet" + august: "Août" + september: "Septembre" + october: "Octobre" + november: "Novembre" + december: "Décembre" diff --git a/crates/router/locales/fr.yml b/crates/router/locales/fr.yml new file mode 100644 index 0000000000..d12dc361d4 --- /dev/null +++ b/crates/router/locales/fr.yml @@ -0,0 +1,42 @@ +_version: 1 + +payout_link: + initiate: + not_allowed: "Vous n'êtes pas autorisé à voir ce contenu" + title: "Liens de Paiement" + status: + title: "Statut de Paiement" + info: + ref_id: "Id de Réf" + error_code: "Code d'Erreur" + error_message: "Message d'Erreur" + message: + failed: "Échec du traitement de votre paiement. Veuillez vérifier auprès de votre fournisseur pour plus de détails." + processing: "Votre paiement devrait être traité dans les 2 à 3 jours ouvrables." + success: "Votre paiement a été effectué sur le mode de paiement sélectionné." + redirection_text: + redirecting: "Redirection ..." + redirecting_in: "Redirection dans" + seconds: "secondes ..." + text: + failed: "Échec du Paiement" + processing: "Traitement du Paiement" + success: "Paiement Réussi" + +time: + am: "AM" + pm: "PM" + +months: + january: "Janvier" + february: "Février" + march: "Mars" + april: "Avril" + may: "Mai" + june: "Juin" + july: "Juillet" + august: "Août" + september: "Septembre" + october: "Octobre" + november: "Novembre" + december: "Décembre" diff --git a/crates/router/locales/he.yml b/crates/router/locales/he.yml new file mode 100644 index 0000000000..dbb3da209c --- /dev/null +++ b/crates/router/locales/he.yml @@ -0,0 +1,42 @@ +_version: 1 + +payout_link: + initiate: + not_allowed: "אינך מורשה לצפות בתוכן זה" + title: "קישורי תשלום" + status: + title: "סטטוס תשלום" + info: + ref_id: "מספר הפניה" + error_code: "קוד שגיאה" + error_message: "הודעת שגיאה" + message: + failed: "נכשל בעיבוד התשלום שלך. אנא בדוק עם הספק שלך למידע נוסף." + processing: "התשלום שלך צריך להיות מעובד בתוך 2-3 ימי עסקים." + success: "התשלום שלך בוצע לשיטת התשלום שנבחרה." + redirection_text: + redirecting: "מופנה..." + redirecting_in: "מופנה בעוד" + seconds: "שניות..." + text: + failed: "תשלום נכשל" + processing: "תשלום בתהליך" + success: "תשלום הצליח" + +time: + am: "בבוקר" + pm: "בערב" + +months: + january: "ינואר" + february: "פברואר" + march: "מרץ" + april: "אפריל" + may: "מאי" + june: "יוני" + july: "יולי" + august: "אוגוסט" + september: "ספטמבר" + october: "אוקטובר" + november: "נובמבר" + december: "דצמבר" diff --git a/crates/router/locales/it.yml b/crates/router/locales/it.yml new file mode 100644 index 0000000000..21f36a9af5 --- /dev/null +++ b/crates/router/locales/it.yml @@ -0,0 +1,42 @@ +_version: 1 + +payout_link: + initiate: + not_allowed: "Non sei autorizzato a visualizzare questo contenuto" + title: "Link di Pagamento" + status: + title: "Stato del Pagamento" + info: + ref_id: "ID di Riferimento" + error_code: "Codice di Errore" + error_message: "Messaggio di Errore" + message: + failed: "Impossibile elaborare il tuo pagamento. Contatta il tuo fornitore per ulteriori dettagli." + processing: "Il tuo pagamento dovrebbe essere elaborato entro 2-3 giorni lavorativi." + success: "Il tuo pagamento è stato effettuato al metodo di pagamento selezionato." + redirection_text: + redirecting: "Reindirizzamento..." + redirecting_in: "Reindirizzamento tra" + seconds: "secondi..." + text: + failed: "Pagamento Fallito" + processing: "Pagamento in Corso" + success: "Pagamento Riuscito" + +time: + am: "AM" + pm: "PM" + +months: + january: "Gennaio" + february: "Febbraio" + march: "Marzo" + april: "Aprile" + may: "Maggio" + june: "Giugno" + july: "Luglio" + august: "Agosto" + september: "Settembre" + october: "Ottobre" + november: "Novembre" + december: "Dicembre" diff --git a/crates/router/locales/ja.yml b/crates/router/locales/ja.yml new file mode 100644 index 0000000000..4691374297 --- /dev/null +++ b/crates/router/locales/ja.yml @@ -0,0 +1,42 @@ +_version: 1 + +payout_link: + initiate: + not_allowed: "このコンテンツを見ることはできません" + title: "支払いリンク" + status: + title: "支払いステータス" + info: + ref_id: "参照ID" + error_code: "エラーコード" + error_message: "エラーメッセージ" + message: + failed: "支払いの処理に失敗しました。詳細については提供者に確認してください。" + processing: "支払いは2〜3営業日以内に処理される予定です。" + success: "支払いが選択した支払い方法に対して行われました。" + redirection_text: + redirecting: "リダイレクト中..." + redirecting_in: "リダイレクトまで" + seconds: "秒..." + text: + failed: "支払い失敗" + processing: "支払い処理中" + success: "支払い成功" + +time: + am: "AM" + pm: "PM" + +months: + january: "1月" + february: "2月" + march: "3月" + april: "4月" + may: "5月" + june: "6月" + july: "7月" + august: "8月" + september: "9月" + october: "10月" + november: "11月" + december: "12月" diff --git a/crates/router/locales/nl.yml b/crates/router/locales/nl.yml new file mode 100644 index 0000000000..1cf808d393 --- /dev/null +++ b/crates/router/locales/nl.yml @@ -0,0 +1,42 @@ +_version: 1 + +payout_link: + initiate: + not_allowed: "Je bent niet toegestaan om deze inhoud te bekijken" + title: "Betalingslinks" + status: + title: "Betalingsstatus" + info: + ref_id: "Referentie-ID" + error_code: "Foutcode" + error_message: "Foutmelding" + message: + failed: "Het is niet gelukt om je betaling te verwerken. Controleer bij je aanbieder voor meer details." + processing: "Je betaling moet binnen 2-3 werkdagen worden verwerkt." + success: "Je betaling is uitgevoerd naar de geselecteerde betaalmethode." + redirection_text: + redirecting: "Doorverwijzen..." + redirecting_in: "Doorverwijzen in" + seconds: "seconden..." + text: + failed: "Betaling Mislukt" + processing: "Betaling in Behandeling" + success: "Betaling Succesvol" + +time: + am: "AM" + pm: "PM" + +months: + january: "Januari" + february: "Februari" + march: "Maart" + april: "April" + may: "Mei" + june: "Juni" + july: "Juli" + august: "Augustus" + september: "September" + october: "Oktober" + november: "November" + december: "December" diff --git a/crates/router/locales/pl.yml b/crates/router/locales/pl.yml new file mode 100644 index 0000000000..71faae3594 --- /dev/null +++ b/crates/router/locales/pl.yml @@ -0,0 +1,42 @@ +_version: 1 + +payout_link: + initiate: + not_allowed: "Nie masz uprawnień do wyświetlania tej treści" + title: "Linki do wypłat" + status: + title: "Status wypłaty" + info: + ref_id: "ID referencyjny" + error_code: "Kod błędu" + error_message: "Komunikat o błędzie" + message: + failed: "Nie udało się przetworzyć Twojej wypłaty. Skontaktuj się z dostawcą w celu uzyskania szczegółowych informacji." + processing: "Twoja wypłata powinna zostać przetworzona w ciągu 2-3 dni roboczych." + success: "Twoja wypłata została zrealizowana metodą płatności, którą wybrałeś." + redirection_text: + redirecting: "Przekierowywanie..." + redirecting_in: "Przekierowywanie za" + seconds: "sekund..." + text: + failed: "Wypłata Nieudana" + processing: "Wypłata w Trakcie" + success: "Wypłata Udała się" + +time: + am: "AM" + pm: "PM" + +months: + january: "Styczeń" + february: "Luty" + march: "Marzec" + april: "Kwiecień" + may: "Maj" + june: "Czerwiec" + july: "Lipiec" + august: "Sierpień" + september: "Wrzesień" + october: "Październik" + november: "Listopad" + december: "Grudzień" diff --git a/crates/router/locales/pt.yml b/crates/router/locales/pt.yml new file mode 100644 index 0000000000..8a419c2df2 --- /dev/null +++ b/crates/router/locales/pt.yml @@ -0,0 +1,42 @@ +_version: 1 + +payout_link: + initiate: + not_allowed: "Você não tem permissão para visualizar este conteúdo" + title: "Links de Pagamento" + status: + title: "Status do Pagamento" + info: + ref_id: "ID de Referência" + error_code: "Código de Erro" + error_message: "Mensagem de Erro" + message: + failed: "Falha ao processar seu pagamento. Verifique com seu provedor para mais detalhes." + processing: "Seu pagamento deve ser processado em 2-3 dias úteis." + success: "Seu pagamento foi realizado no método de pagamento selecionado." + redirection_text: + redirecting: "Redirecionando..." + redirecting_in: "Redirecionando em" + seconds: "segundos..." + text: + failed: "Falha no Pagamento" + processing: "Pagamento em Processamento" + success: "Pagamento Bem-Sucedido" + +time: + am: "AM" + pm: "PM" + +months: + january: "Janeiro" + february: "Fevereiro" + march: "Março" + april: "Abril" + may: "Maio" + june: "Junho" + july: "Julho" + august: "Agosto" + september: "Setembro" + october: "Outubro" + november: "Novembro" + december: "Dezembro" diff --git a/crates/router/locales/ru.yml b/crates/router/locales/ru.yml new file mode 100644 index 0000000000..8257ee6702 --- /dev/null +++ b/crates/router/locales/ru.yml @@ -0,0 +1,42 @@ +_version: 1 + +payout_link: + initiate: + not_allowed: "Вам не разрешено просматривать этот контент" + title: "Ссылки на выплаты" + status: + title: "Статус выплаты" + info: + ref_id: "ID ссылки" + error_code: "Код ошибки" + error_message: "Сообщение об ошибке" + message: + failed: "Не удалось обработать вашу выплату. Пожалуйста, проверьте у вашего поставщика более подробную информацию." + processing: "Ваша выплата должна быть обработана в течение 2-3 рабочих дней." + success: "Ваша выплата была произведена на выбранный метод оплаты." + redirection_text: + redirecting: "Перенаправление..." + redirecting_in: "Перенаправление через" + seconds: "секунд..." + text: + failed: "Выплата не удалась" + processing: "Выплата в процессе" + success: "Выплата успешна" + +time: + am: "AM" + pm: "PM" + +months: + january: "Январь" + february: "Февраль" + march: "Март" + april: "Апрель" + may: "Май" + june: "Июнь" + july: "Июль" + august: "Август" + september: "Сентябрь" + october: "Октябрь" + november: "Ноябрь" + december: "Декабрь" diff --git a/crates/router/locales/sv.yml b/crates/router/locales/sv.yml new file mode 100644 index 0000000000..8c053a2b09 --- /dev/null +++ b/crates/router/locales/sv.yml @@ -0,0 +1,42 @@ +_version: 1 + +payout_link: + initiate: + not_allowed: "Du har inte tillåtelse att visa detta innehåll" + title: "Utbetalningslänkar" + status: + title: "Utbetalningsstatus" + info: + ref_id: "Referens-ID" + error_code: "Felkod" + error_message: "Felmeddelande" + message: + failed: "Det gick inte att behandla din utbetalning. Kontrollera med din leverantör för mer information." + processing: "Din utbetalning bör behandlas inom 2-3 arbetsdagar." + success: "Din utbetalning har genomförts till vald betalningsmetod." + redirection_text: + redirecting: "Omdirigerar..." + redirecting_in: "Omdirigerar om" + seconds: "sekunder..." + text: + failed: "Utbetalning Misslyckades" + processing: "Utbetalning Under Behandling" + success: "Utbetalning Lyckad" + +time: + am: "AM" + pm: "PM" + +months: + january: "Januari" + february: "Februari" + march: "Mars" + april: "April" + may: "Maj" + june: "Juni" + july: "Juli" + august: "Augusti" + september: "September" + october: "Oktober" + november: "November" + december: "December" diff --git a/crates/router/locales/zh.yml b/crates/router/locales/zh.yml new file mode 100644 index 0000000000..ce7cd3d3f9 --- /dev/null +++ b/crates/router/locales/zh.yml @@ -0,0 +1,42 @@ +_version: 1 + +payout_link: + initiate: + not_allowed: "您没有权限查看此内容" + title: "支付链接" + status: + title: "支付状态" + info: + ref_id: "参考ID" + error_code: "错误代码" + error_message: "错误信息" + message: + failed: "处理您的支付时失败。请与您的服务提供商确认更多详细信息。" + processing: "您的支付应在2-3个工作日内处理完毕。" + success: "您的支付已成功完成,使用了选定的支付方式。" + redirection_text: + redirecting: "正在重定向..." + redirecting_in: "重定向中" + seconds: "秒..." + text: + failed: "支付失败" + processing: "支付处理中" + success: "支付成功" + +time: + am: "AM" + pm: "PM" + +months: + january: "一月" + february: "二月" + march: "三月" + april: "四月" + may: "五月" + june: "六月" + july: "七月" + august: "八月" + september: "九月" + october: "十月" + november: "十一月" + december: "十二月" diff --git a/crates/router/src/compatibility/wrap.rs b/crates/router/src/compatibility/wrap.rs index ec43259ad2..2c1dea5f6d 100644 --- a/crates/router/src/compatibility/wrap.rs +++ b/crates/router/src/compatibility/wrap.rs @@ -142,6 +142,7 @@ where let link_type = (boxed_generic_link_data).data.to_string(); match services::generic_link_response::build_generic_link_html( boxed_generic_link_data.data, + boxed_generic_link_data.locale, ) { Ok(rendered_html) => api::http_response_html_data(rendered_html, None), Err(_) => { diff --git a/crates/router/src/core/generic_link/payout_link/initiate/index.html b/crates/router/src/core/generic_link/payout_link/initiate/index.html index 1857e497d3..fe574c37c3 100644 --- a/crates/router/src/core/generic_link/payout_link/initiate/index.html +++ b/crates/router/src/core/generic_link/payout_link/initiate/index.html @@ -3,7 +3,7 @@ - Payout Links + {{ i18n_payout_link_title }} {{ css_style_tag }} diff --git a/crates/router/src/core/generic_link/payout_link/initiate/script.js b/crates/router/src/core/generic_link/payout_link/initiate/script.js index 731f3f76d0..2327bfba13 100644 --- a/crates/router/src/core/generic_link/payout_link/initiate/script.js +++ b/crates/router/src/core/generic_link/payout_link/initiate/script.js @@ -14,7 +14,7 @@ try { // Remove the script from DOM incase it's not iframed if (!isFramed) { function initializePayoutSDK() { - var errMsg = "You are not allowed to view this content."; + var errMsg = "{{i18n_not_allowed}}"; var contentElement = document.getElementById("payout-link"); if (contentElement instanceof HTMLDivElement) { contentElement.innerHTML = errMsg; @@ -34,25 +34,25 @@ if (!isFramed) { **/ function formatDate(date) { var months = [ - "January", - "February", - "March", - "April", - "May", - "June", - "July", - "August", - "September", - "October", - "November", - "December", + "{{i18n_january}}", + "{{i18n_february}}", + "{{i18n_march}}", + "{{i18n_april}}", + "{{i18n_may}}", + "{{i18n_june}}", + "{{i18n_july}}", + "{{i18n_august}}", + "{{i18n_september}}", + "{{i18n_october}}", + "{{i18n_november}}", + "{{i18n_december}}", ]; var hours = date.getHours(); var minutes = date.getMinutes(); // @ts-ignore minutes = minutes < 10 ? "0" + minutes : minutes; - var suffix = hours > 11 ? "PM" : "AM"; + var suffix = hours > 11 ? "{{i18n_pm}}" : "{{i18n_am}}"; hours = hours % 12; hours = hours ? hours : 12; var day = date.getDate(); @@ -127,6 +127,7 @@ if (!isFramed) { // @ts-ignore var payoutDetails = window.__PAYOUT_DETAILS; var clientSecret = payoutDetails.client_secret; + var locale = payoutDetails.locale; var publishableKey = payoutDetails.publishable_key; var appearance = { variables: { @@ -143,6 +144,7 @@ if (!isFramed) { widgets = hyper.widgets({ appearance: appearance, clientSecret: clientSecret, + locale: locale, }); // Create payment method collect widget diff --git a/crates/router/src/core/generic_link/payout_link/status/index.html b/crates/router/src/core/generic_link/payout_link/status/index.html index f0fb564f64..4a4f026056 100644 --- a/crates/router/src/core/generic_link/payout_link/status/index.html +++ b/crates/router/src/core/generic_link/payout_link/status/index.html @@ -3,7 +3,7 @@ - Payout Status + {{ i18n_payout_link_status_title }} {{ css_style_tag }} diff --git a/crates/router/src/core/generic_link/payout_link/status/script.js b/crates/router/src/core/generic_link/payout_link/status/script.js index 829006a431..42b5790359 100644 --- a/crates/router/src/core/generic_link/payout_link/status/script.js +++ b/crates/router/src/core/generic_link/payout_link/status/script.js @@ -69,8 +69,8 @@ function renderStatusDetails(payoutDetails) { var statusInfo = { statusImageSrc: "https://live.hyperswitch.io/payment-link-assets/success.png", - statusText: "Payout Successful", - statusMessage: "Your payout was made to selected payment method.", + statusText: "{{i18n_success_text}}", + statusMessage: "{{i18n_success_message}}", }; switch (status) { case "success": @@ -80,9 +80,8 @@ function renderStatusDetails(payoutDetails) { case "pending": statusInfo.statusImageSrc = "https://live.hyperswitch.io/payment-link-assets/pending.png"; - statusInfo.statusText = "Payout Processing"; - statusInfo.statusMessage = - "Your payout should be processed within 2-3 business days."; + statusInfo.statusText = "{{i18n_pending_text}}"; + statusInfo.statusMessage = "{{i18n_pending_message}}"; break; case "failed": case "cancelled": @@ -96,9 +95,8 @@ function renderStatusDetails(payoutDetails) { default: statusInfo.statusImageSrc = "https://live.hyperswitch.io/payment-link-assets/failed.png"; - statusInfo.statusText = "Payout Failed"; - statusInfo.statusMessage = - "Failed to process your payout. Please check with your provider for more details."; + statusInfo.statusText = "{{i18n_failed_text}}"; + statusInfo.statusMessage = "{{i18n_failed_message}}"; break; } @@ -120,13 +118,13 @@ function renderStatusDetails(payoutDetails) { } var resourceInfo = { - "Ref Id": payoutDetails.payout_id, + "{{i18n_ref_id_text}}": payoutDetails.payout_id, }; if (typeof payoutDetails.error_code === "string") { - resourceInfo["Error Code"] = payoutDetails.error_code; + resourceInfo["{{i18n_error_code_text}}"] = payoutDetails.error_code; } if (typeof payoutDetails.error_message === "string") { - resourceInfo["Error Message"] = payoutDetails.error_message; + resourceInfo["{{i18n_error_message}}"] = payoutDetails.error_message; } var resourceNode = document.createElement("div"); resourceNode.id = "resource-info-container"; @@ -166,8 +164,10 @@ function redirectToEndUrl(returnUrl) { var secondsLeft = timeout - j++; var innerText = secondsLeft === 0 - ? "Redirecting ..." - : "Redirecting in " + secondsLeft + " seconds ..."; + ? "{{i18n_redirecting_text}}" + : "{{i18n_redirecting_in_text}} " + + secondsLeft + + " {{i18n_seconds_text}} ..."; if (statusRedirectTextNode instanceof HTMLDivElement) { statusRedirectTextNode.innerText = innerText; } diff --git a/crates/router/src/core/payment_link.rs b/crates/router/src/core/payment_link.rs index 643b69511c..df87637f4e 100644 --- a/crates/router/src/core/payment_link.rs +++ b/crates/router/src/core/payment_link.rs @@ -7,8 +7,9 @@ use api_models::{ use common_utils::{ consts::{ DEFAULT_ALLOWED_DOMAINS, DEFAULT_BACKGROUND_COLOR, DEFAULT_DISPLAY_SDK_ONLY, - DEFAULT_ENABLE_SAVED_PAYMENT_METHOD, DEFAULT_MERCHANT_LOGO, DEFAULT_PRODUCT_IMG, - DEFAULT_SDK_LAYOUT, DEFAULT_SESSION_EXPIRY, DEFAULT_TRANSACTION_DETAILS, + DEFAULT_ENABLE_SAVED_PAYMENT_METHOD, DEFAULT_LOCALE, DEFAULT_MERCHANT_LOGO, + DEFAULT_PRODUCT_IMG, DEFAULT_SDK_LAYOUT, DEFAULT_SESSION_EXPIRY, + DEFAULT_TRANSACTION_DETAILS, }, ext_traits::{OptionExt, ValueExt}, types::{AmountConvertor, MinorUnit, StringMajorUnitForCore}, @@ -342,6 +343,7 @@ pub async fn initiate_secure_payment_link_flow( let link_data = GenericLinks { allowed_domains, data: GenericLinksData::SecurePaymentLink(payment_link_data), + locale: DEFAULT_LOCALE.to_string(), }; logger::info!( "payment link data, for building secure payment link {:?}", diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs index a33fe5bb06..977727d911 100644 --- a/crates/router/src/core/payment_methods.rs +++ b/crates/router/src/core/payment_methods.rs @@ -12,7 +12,7 @@ pub use api_models::enums::Connector; use api_models::payment_methods; #[cfg(feature = "payouts")] pub use api_models::{enums::PayoutConnectors, payouts as payout_types}; -use common_utils::{ext_traits::Encode, id_type::CustomerId}; +use common_utils::{consts::DEFAULT_LOCALE, ext_traits::Encode, id_type::CustomerId}; use diesel_models::{ enums, GenericLinkNew, PaymentMethodCollectLink, PaymentMethodCollectLinkData, }; @@ -251,6 +251,7 @@ pub async fn render_pm_collect_link( GenericLinks { allowed_domains: HashSet::from([]), data: GenericLinksData::ExpiredLink(expired_link_data), + locale: DEFAULT_LOCALE.to_string(), }, ))) @@ -312,8 +313,8 @@ pub async fn render_pm_collect_link( Ok(services::ApplicationResponse::GenericLinkForm(Box::new( GenericLinks { allowed_domains: HashSet::from([]), - data: GenericLinksData::PaymentMethodCollect(generic_form_data), + locale: DEFAULT_LOCALE.to_string(), }, ))) } @@ -357,8 +358,8 @@ pub async fn render_pm_collect_link( Ok(services::ApplicationResponse::GenericLinkForm(Box::new( GenericLinks { allowed_domains: HashSet::from([]), - data: GenericLinksData::PaymentMethodCollectStatus(generic_status_data), + locale: DEFAULT_LOCALE.to_string(), }, ))) } diff --git a/crates/router/src/core/payout_link.rs b/crates/router/src/core/payout_link.rs index da34a82a85..1b9445f180 100644 --- a/crates/router/src/core/payout_link.rs +++ b/crates/router/src/core/payout_link.rs @@ -30,6 +30,7 @@ pub async fn initiate_payout_link( key_store: domain::MerchantKeyStore, req: payouts::PayoutLinkInitiateRequest, request_headers: &header::HeaderMap, + locale: String, ) -> RouterResponse { let db: &dyn StorageInterface = &*state.store; let merchant_id = merchant_account.get_id(); @@ -108,6 +109,7 @@ pub async fn initiate_payout_link( GenericLinks { allowed_domains: (link_data.allowed_domains), data: GenericLinksData::ExpiredLink(expired_link_data), + locale, }, ))) } @@ -187,6 +189,7 @@ pub async fn initiate_payout_link( enabled_payment_methods, amount, currency: payout.destination_currency, + locale: locale.clone(), }; let serialized_css_content = String::new(); @@ -209,6 +212,7 @@ pub async fn initiate_payout_link( GenericLinks { allowed_domains: (link_data.allowed_domains), data: GenericLinksData::PayoutLink(generic_form_data), + locale, }, ))) } @@ -251,6 +255,7 @@ pub async fn initiate_payout_link( GenericLinks { allowed_domains: (link_data.allowed_domains), data: GenericLinksData::PayoutLinkStatus(generic_status_data), + locale, }, ))) } diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index 2debb492ad..07b50d3a15 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -300,6 +300,7 @@ pub async fn payouts_create_core( merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, req: payouts::PayoutCreateRequest, + locale: &String, ) -> RouterResponse { // Validate create request let (payout_id, payout_method_data, profile_id, customer) = @@ -314,6 +315,7 @@ pub async fn payouts_create_core( &payout_id, &profile_id, payout_method_data.as_ref(), + locale, customer.as_ref(), ) .await?; @@ -2206,6 +2208,7 @@ pub async fn payout_create_db_entries( payout_id: &String, profile_id: &String, stored_payout_method_data: Option<&payouts::PayoutMethodData>, + locale: &String, customer: Option<&domain::Customer>, ) -> RouterResult { let db = &*state.store; @@ -2227,6 +2230,7 @@ pub async fn payout_create_db_entries( merchant_id, req, payout_id, + locale, ) .await?, ), @@ -2552,6 +2556,7 @@ pub async fn create_payout_link( merchant_id: &common_utils::id_type::MerchantId, req: &payouts::PayoutCreateRequest, payout_id: &String, + locale: &String, ) -> RouterResult { let payout_link_config_req = req.payout_link_config.to_owned(); @@ -2595,8 +2600,9 @@ pub async fn create_payout_link( .as_ref() .map_or(default_config.expiry, |expiry| *expiry); let url = format!( - "{base_url}/payout_link/{}/{payout_id}", - merchant_id.get_string_repr() + "{base_url}/payout_link/{}/{payout_id}?locale={}", + merchant_id.get_string_repr(), + locale ); let link = url::Url::parse(&url) .change_context(errors::ApiErrorResponse::InternalServerError) diff --git a/crates/router/src/lib.rs b/crates/router/src/lib.rs index 9691a53662..9f41983102 100644 --- a/crates/router/src/lib.rs +++ b/crates/router/src/lib.rs @@ -11,6 +11,7 @@ pub mod core; pub mod cors; pub mod db; pub mod env; +pub mod locale; pub(crate) mod macros; pub mod routes; @@ -44,6 +45,9 @@ use crate::{configs::settings, core::errors}; #[global_allocator] static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc; +// Import translate fn in root +use crate::locale::{_rust_i18n_t, _rust_i18n_try_translate}; + /// Header Constants pub mod headers { pub const ACCEPT: &str = "Accept"; diff --git a/crates/router/src/locale.rs b/crates/router/src/locale.rs new file mode 100644 index 0000000000..9496143450 --- /dev/null +++ b/crates/router/src/locale.rs @@ -0,0 +1,3 @@ +use rust_i18n::i18n; + +i18n!("locales", fallback = "en"); diff --git a/crates/router/src/routes.rs b/crates/router/src/routes.rs index 304a0cde0b..561f96ab71 100644 --- a/crates/router/src/routes.rs +++ b/crates/router/src/routes.rs @@ -28,6 +28,7 @@ pub mod metrics; pub mod payment_link; pub mod payment_methods; pub mod payments; +#[cfg(feature = "payouts")] pub mod payout_link; #[cfg(feature = "payouts")] pub mod payouts; diff --git a/crates/router/src/routes/payout_link.rs b/crates/router/src/routes/payout_link.rs index 7bac4c5519..8715743572 100644 --- a/crates/router/src/routes/payout_link.rs +++ b/crates/router/src/routes/payout_link.rs @@ -1,17 +1,17 @@ -#[cfg(feature = "payouts")] use actix_web::{web, Responder}; -#[cfg(feature = "payouts")] use api_models::payouts::PayoutLinkInitiateRequest; -#[cfg(feature = "payouts")] +use common_utils::consts::DEFAULT_LOCALE; use router_env::Flow; -#[cfg(feature = "payouts")] use crate::{ core::{api_locking, payout_link::*}, - services::{api, authentication as auth}, + headers::ACCEPT_LANGUAGE, + services::{ + api, + authentication::{self as auth, get_header_value_by_key}, + }, AppState, }; -#[cfg(feature = "payouts")] pub async fn render_payout_link( state: web::Data, req: actix_web::HttpRequest, @@ -24,13 +24,25 @@ pub async fn render_payout_link( payout_id, }; let headers = req.headers(); + let locale = get_header_value_by_key(ACCEPT_LANGUAGE.into(), headers) + .ok() + .flatten() + .map(|val| val.to_string()) + .unwrap_or(DEFAULT_LOCALE.to_string()); Box::pin(api::server_wrap( flow, state, &req, payload.clone(), |state, auth, req, _| { - initiate_payout_link(state, auth.merchant_account, auth.key_store, req, headers) + initiate_payout_link( + state, + auth.merchant_account, + auth.key_store, + req, + headers, + locale.clone(), + ) }, &auth::MerchantIdAuth(merchant_id), api_locking::LockAction::NotApplicable, diff --git a/crates/router/src/routes/payouts.rs b/crates/router/src/routes/payouts.rs index 3c3d0f0a16..40c2e36cc5 100644 --- a/crates/router/src/routes/payouts.rs +++ b/crates/router/src/routes/payouts.rs @@ -2,6 +2,7 @@ use actix_web::{ body::{BoxBody, MessageBody}, web, HttpRequest, HttpResponse, Responder, }; +use common_utils::consts; use router_env::{instrument, tracing, Flow}; use super::app::AppState; @@ -9,7 +10,12 @@ use super::app::AppState; use crate::types::api::payments as payment_types; use crate::{ core::{api_locking, payouts::*}, - services::{api, authentication as auth, authorization::permissions::Permission}, + headers::ACCEPT_LANGUAGE, + services::{ + api, + authentication::{self as auth, get_header_value_by_key}, + authorization::permissions::Permission, + }, types::api::payouts as payout_types, }; @@ -21,13 +27,18 @@ pub async fn payouts_create( json_payload: web::Json, ) -> HttpResponse { let flow = Flow::PayoutsCreate; + let locale = get_header_value_by_key(ACCEPT_LANGUAGE.into(), req.headers()) + .ok() + .flatten() + .map(|val| val.to_string()) + .unwrap_or(consts::DEFAULT_LOCALE.to_string()); Box::pin(api::server_wrap( flow, state, &req, json_payload.into_inner(), |state, auth, req, _| { - payouts_create_core(state, auth.merchant_account, auth.key_store, req) + payouts_create_core(state, auth.merchant_account, auth.key_store, req, &locale) }, &auth::HeaderAuth(auth::ApiKeyAuth), api_locking::LockAction::NotApplicable, diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs index c715594e8d..b2571e6623 100644 --- a/crates/router/src/services/api.rs +++ b/crates/router/src/services/api.rs @@ -982,7 +982,10 @@ where Ok(ApplicationResponse::GenericLinkForm(boxed_generic_link_data)) => { let link_type = boxed_generic_link_data.data.to_string(); - match build_generic_link_html(boxed_generic_link_data.data) { + match build_generic_link_html( + boxed_generic_link_data.data, + boxed_generic_link_data.locale, + ) { Ok(rendered_html) => { let headers = if !boxed_generic_link_data.allowed_domains.is_empty() { let domains_str = boxed_generic_link_data diff --git a/crates/router/src/services/api/generic_link_response.rs b/crates/router/src/services/api/generic_link_response.rs index f180e3d3f3..c47539eb8d 100644 --- a/crates/router/src/services/api/generic_link_response.rs +++ b/crates/router/src/services/api/generic_link_response.rs @@ -7,9 +7,11 @@ use tera::{Context, Tera}; use super::build_secure_payment_link_html; use crate::core::errors; +pub mod context; pub fn build_generic_link_html( boxed_generic_link_data: GenericLinksData, + locale: String, ) -> CustomResult { match boxed_generic_link_data { GenericLinksData::ExpiredLink(link_data) => build_generic_expired_link_html(&link_data), @@ -20,10 +22,12 @@ pub fn build_generic_link_html( GenericLinksData::PaymentMethodCollectStatus(pm_collect_data) => { build_pm_collect_link_status_html(&pm_collect_data) } - GenericLinksData::PayoutLink(payout_link_data) => build_payout_link_html(&payout_link_data), + GenericLinksData::PayoutLink(payout_link_data) => { + build_payout_link_html(&payout_link_data, locale.as_str()) + } GenericLinksData::PayoutLinkStatus(pm_collect_data) => { - build_payout_link_status_html(&pm_collect_data) + build_payout_link_status_html(&pm_collect_data, locale.as_str()) } GenericLinksData::SecurePaymentLink(payment_link_data) => { build_secure_payment_link_html(payment_link_data) @@ -52,7 +56,6 @@ pub fn build_generic_expired_link_html( fn build_html_template( link_data: &GenericLinkFormData, document: &'static str, - script: &'static str, styles: &'static str, ) -> CustomResult<(Tera, Context), errors::ApiErrorResponse> { let mut tera: Tera = Tera::default(); @@ -65,42 +68,43 @@ fn build_html_template( let _ = tera.add_raw_template("document_styles", &final_css); context.insert("color_scheme", &link_data.css_data); - // Insert dynamic context in JS - let js_dynamic_context = "{{ script_data }}"; - let js_template = script.to_string(); - let final_js = format!("{}\n{}", js_dynamic_context, js_template); - let _ = tera.add_raw_template("document_scripts", &final_js); - context.insert("script_data", &link_data.js_data); - let css_style_tag = tera .render("document_styles", &context) .map(|css| format!("", css)) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed to render CSS template")?; - let js_script_tag = tera - .render("document_scripts", &context) - .map(|js| format!("", js)) - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed to render JS template")?; - // Insert HTML context let html_template = document.to_string(); let _ = tera.add_raw_template("html_template", &html_template); context.insert("css_style_tag", &css_style_tag); - context.insert("js_script_tag", &js_script_tag); Ok((tera, context)) } pub fn build_payout_link_html( link_data: &GenericLinkFormData, + locale: &str, ) -> CustomResult { let document = include_str!("../../core/generic_link/payout_link/initiate/index.html"); - let script = include_str!("../../core/generic_link/payout_link/initiate/script.js"); let styles = include_str!("../../core/generic_link/payout_link/initiate/styles.css"); - let (tera, mut context) = build_html_template(link_data, document, script, styles) + let (mut tera, mut context) = build_html_template(link_data, document, styles) .attach_printable("Failed to build context for payout link's HTML template")?; + + // Insert dynamic context in JS + let script = include_str!("../../core/generic_link/payout_link/initiate/script.js"); + let js_template = script.to_string(); + let js_dynamic_context = "{{ script_data }}"; + let final_js = format!("{}\n{}", js_dynamic_context, js_template); + let _ = tera.add_raw_template("document_scripts", &final_js); + context.insert("script_data", &link_data.js_data); + context::insert_locales_in_context_for_payout_link(&mut context, locale); + let js_script_tag = tera + .render("document_scripts", &context) + .map(|js| format!("", js)) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to render JS template")?; + context.insert("js_script_tag", &js_script_tag); context.insert( "hyper_sdk_loader_script_tag", &format!( @@ -109,6 +113,7 @@ pub fn build_payout_link_html( ), ); + // Render HTML template tera.render("html_template", &context) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed to render payout link's HTML template") @@ -119,12 +124,25 @@ pub fn build_pm_collect_link_html( ) -> CustomResult { let document = include_str!("../../core/generic_link/payment_method_collect/initiate/index.html"); - let script = include_str!("../../core/generic_link/payment_method_collect/initiate/script.js"); let styles = include_str!("../../core/generic_link/payment_method_collect/initiate/styles.css"); - let (tera, mut context) = build_html_template(link_data, document, script, styles) + let (mut tera, mut context) = build_html_template(link_data, document, styles) .attach_printable( "Failed to build context for payment method collect link's HTML template", )?; + + // Insert dynamic context in JS + let script = include_str!("../../core/generic_link/payment_method_collect/initiate/script.js"); + let js_template = script.to_string(); + let js_dynamic_context = "{{ script_data }}"; + let final_js = format!("{}\n{}", js_dynamic_context, js_template); + let _ = tera.add_raw_template("document_scripts", &final_js); + context.insert("script_data", &link_data.js_data); + let js_script_tag = tera + .render("document_scripts", &context) + .map(|js| format!("", js)) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to render JS template")?; + context.insert("js_script_tag", &js_script_tag); context.insert( "hyper_sdk_loader_script_tag", &format!( @@ -133,6 +151,7 @@ pub fn build_pm_collect_link_html( ), ); + // Render HTML template tera.render("html_template", &context) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed to render payment method collect link's HTML template") @@ -140,6 +159,7 @@ pub fn build_pm_collect_link_html( pub fn build_payout_link_status_html( link_data: &GenericLinkStatusData, + locale: &str, ) -> CustomResult { let mut tera = Tera::default(); let mut context = Context::new(); @@ -159,13 +179,13 @@ pub fn build_payout_link_status_html( .attach_printable("Failed to render payout link status CSS template")?; // Insert dynamic context in JS - let js_dynamic_context = "{{ collect_link_status_context }}"; + let js_dynamic_context = "{{ script_data }}"; let js_template = include_str!("../../core/generic_link/payout_link/status/script.js").to_string(); let final_js = format!("{}\n{}", js_dynamic_context, js_template); let _ = tera.add_raw_template("payout_link_status_script", &final_js); - context.insert("collect_link_status_context", &link_data.js_data); - + context.insert("script_data", &link_data.js_data); + context::insert_locales_in_context_for_payout_link_status(&mut context, locale); let js_script_tag = tera .render("payout_link_status_script", &context) .map(|js| format!("", js)) diff --git a/crates/router/src/services/api/generic_link_response/context.rs b/crates/router/src/services/api/generic_link_response/context.rs new file mode 100644 index 0000000000..1ea45bd108 --- /dev/null +++ b/crates/router/src/services/api/generic_link_response/context.rs @@ -0,0 +1,80 @@ +use rust_i18n::t; +use tera::Context; + +pub fn insert_locales_in_context_for_payout_link(context: &mut Context, locale: &str) { + let i18n_payout_link_title = t!("payout_link.initiate.title", locale = locale); + let i18n_january = t!("months.january", locale = locale); + let i18n_february = t!("months.february", locale = locale); + let i18n_march = t!("months.march", locale = locale); + let i18n_april = t!("months.april", locale = locale); + let i18n_may = t!("months.may", locale = locale); + let i18n_june = t!("months.june", locale = locale); + let i18n_july = t!("months.july", locale = locale); + let i18n_august = t!("months.august", locale = locale); + let i18n_september = t!("months.september", locale = locale); + let i18n_october = t!("months.october", locale = locale); + let i18n_november = t!("months.november", locale = locale); + let i18n_december = t!("months.december", locale = locale); + let i18n_not_allowed = t!("payout_link.initiate.not_allowed", locale = locale); + let i18n_am = t!("time.am", locale = locale); + let i18n_pm = t!("time.pm", locale = locale); + + context.insert("i18n_payout_link_title", &i18n_payout_link_title); + context.insert("i18n_january", &i18n_january); + context.insert("i18n_february", &i18n_february); + context.insert("i18n_march", &i18n_march); + context.insert("i18n_april", &i18n_april); + context.insert("i18n_may", &i18n_may); + context.insert("i18n_june", &i18n_june); + context.insert("i18n_july", &i18n_july); + context.insert("i18n_august", &i18n_august); + context.insert("i18n_september", &i18n_september); + context.insert("i18n_october", &i18n_october); + context.insert("i18n_november", &i18n_november); + context.insert("i18n_december", &i18n_december); + context.insert("i18n_not_allowed", &i18n_not_allowed); + context.insert("i18n_am", &i18n_am); + context.insert("i18n_pm", &i18n_pm); +} + +pub fn insert_locales_in_context_for_payout_link_status(context: &mut Context, locale: &str) { + let i18n_payout_link_status_title = t!("payout_link.status.title", locale = locale); + let i18n_success_text = t!("payout_link.status.text.success", locale = locale); + let i18n_success_message = t!("payout_link.status.message.success", locale = locale); + let i18n_pending_text = t!("payout_link.status.text.pending", locale = locale); + let i18n_pending_message = t!("payout_link.status.message.pending", locale = locale); + let i18n_failed_text = t!("payout_link.status.text.failed", locale = locale); + let i18n_failed_message = t!("payout_link.status.message.failed", locale = locale); + let i18n_ref_id_text = t!("payout_link.status.info.ref_id", locale = locale); + let i18n_error_code_text = t!("payout_link.status.info.error_code", locale = locale); + let i18n_error_message = t!("payout_link.status.info.error_message", locale = locale); + let i18n_redirecting_text = t!( + "payout_link.status.redirection_text.redirecting", + locale = locale + ); + let i18n_redirecting_in_text = t!( + "payout_link.status.redirection_text.redirecting_in", + locale = locale + ); + let i18n_seconds_text = t!( + "payout_link.status.redirection_text.seconds", + locale = locale + ); + + context.insert( + "i18n_payout_link_status_title", + &i18n_payout_link_status_title, + ); + context.insert("i18n_success_text", &i18n_success_text); + context.insert("i18n_success_message", &i18n_success_message); + context.insert("i18n_pending_text", &i18n_pending_text); + context.insert("i18n_pending_message", &i18n_pending_message); + context.insert("i18n_failed_text", &i18n_failed_text); + context.insert("i18n_failed_message", &i18n_failed_message); + context.insert("i18n_ref_id_text", &i18n_ref_id_text); + context.insert("i18n_error_code_text", &i18n_error_code_text); + context.insert("i18n_error_message", &i18n_error_message); + context.insert("i18n_redirecting_text", &i18n_redirecting_text); + context.insert("i18n_redirecting_in_text", &i18n_redirecting_in_text); + context.insert("i18n_seconds_text", &i18n_seconds_text); +}