Bug: [BUG] consider only the language for locale for translations



### Bug Description

`Accept-Language` header is meant for passing locales in the API requests.

Sample - `es-ES` 

In application, the value of this header is consumed as is for language translations (for payment and payout links). However, the language for Spanish will be mapped to `es` rather than the language-location combination, which ends up defaulting to English for such scenarios (as `es-ES` != `es`)

### Expected Behavior

For `es-ES` locale, the translation must be present in Spanish

### Actual Behavior

For `es-ES` locale, the translation is present in English

### Steps To Reproduce

During creation of payment links, pass `Accept-Language: es-ES` in the request.

### Context For The Bug

_No response_

### Environment

Are you using hyperswitch hosted version? Yes/No
If yes, please provide the value of the `x-request-id` response header to help us debug your issue.

If not (or if building/running locally), please provide the following details:
1. Operating System or Linux distribution:
2. Rust version (output of `rustc --version`): ``
3. App version (output of `cargo r --features vergen -- --version`): ``


### Have you spent some time checking if this bug has been raised before?

- [x] I checked and didn't find a similar issue

### Have you read the Contributing Guidelines?

- [x] I have read the [Contributing Guidelines](https://github.com/juspay/hyperswitch/blob/main/docs/CONTRIBUTING.md)

### Are you willing to submit a PR?

Yes, I am willing to submit a PR!
diff --git a/crates/router/locales/en-GB.yml b/crates/router/locales/en_gb.yml
similarity index 100%
rename from crates/router/locales/en-GB.yml
rename to crates/router/locales/en_gb.yml
diff --git a/crates/router/locales/fr-BE.yml b/crates/router/locales/fr_be.yml
similarity index 100%
rename from crates/router/locales/fr-BE.yml
rename to crates/router/locales/fr_be.yml
diff --git a/crates/router/src/core/payment_link/locale.js b/crates/router/src/core/payment_link/locale.js
index f70d9cefbdf..5a404c93a5b 100644
--- a/crates/router/src/core/payment_link/locale.js
+++ b/crates/router/src/core/payment_link/locale.js
@@ -619,8 +619,25 @@ const locales = {
     },
   };
 
-  function getTranslations(locale_str) {
-    var fallback_locale = 'en';
-    var locale = locale_str.toLowerCase().replace(/-/g, "_") || fallback_locale; // defaults if locale is not present in payment details.
-    return locales[locale] || locales['en']; // defaults if locale is not implemented in locales.
-  }
\ No newline at end of file
+function getLanguage(localeStr) {
+  var fallback_locale = 'en';
+  var primaryLocale = (localeStr.toLowerCase() || fallback_locale).split(',')[0].trim();
+  
+  // Split into language and country parts
+  var parts = primaryLocale.split('-');
+  var language = parts[0];
+  var country = parts.length > 1 ? parts[1] : null;
+
+  var key = `${language}_${country}`;
+  switch (key) {
+    case 'en_gb': return 'en_gb';
+    case 'fr_be': return 'fr_be';
+    default: return language;
+  }
+}
+
+function getTranslations(localeStr) {
+  var fallback_locale = 'en';
+  var language = getLanguage(localeStr);
+  return locales[language] || locales[fallback_locale];
+}
\ No newline at end of file
diff --git a/crates/router/src/services/api/generic_link_response/context.rs b/crates/router/src/services/api/generic_link_response/context.rs
index 25d2e3f1662..9589081d07e 100644
--- a/crates/router/src/services/api/generic_link_response/context.rs
+++ b/crates/router/src/services/api/generic_link_response/context.rs
@@ -1,7 +1,29 @@
+use common_utils::consts::DEFAULT_LOCALE;
 use rust_i18n::t;
 use tera::Context;
 
+fn get_language(locale_str: &str) -> String {
+    let lowercase_str = locale_str.to_lowercase();
+    let primary_locale = lowercase_str.split(',').next().unwrap_or("").trim();
+
+    if primary_locale.is_empty() {
+        return DEFAULT_LOCALE.to_string();
+    }
+
+    let parts = primary_locale.split('-').collect::<Vec<&str>>();
+    let language = *parts.first().unwrap_or(&DEFAULT_LOCALE);
+    let country = parts.get(1).copied();
+
+    match (language, country) {
+        ("en", Some("gb")) => "en_gb".to_string(),
+        ("fr", Some("be")) => "fr_be".to_string(),
+        (lang, _) => lang.to_string(),
+    }
+}
+
 pub fn insert_locales_in_context_for_payout_link(context: &mut Context, locale: &str) {
+    let language = get_language(locale);
+    let locale = language.as_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);
@@ -38,6 +60,8 @@ pub fn insert_locales_in_context_for_payout_link(context: &mut Context, locale:
 }
 
 pub fn insert_locales_in_context_for_payout_link_status(context: &mut Context, locale: &str) {
+    let language = get_language(locale);
+    let locale = language.as_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);

## Type of Change
<!-- Put an `x` in the boxes that apply -->
- [x] Bugfix
- [ ] New feature
- [ ] Enhancement
- [ ] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
Fix the locale handling in the payment and payout links translation functionality to properly support language-location combinations like `es-ES`. Currently, the system is using the full locale value from the `Accept-Language` header without parsing it, causing translations for such locales to fail when the header includes region information.

The fix extracts the base language code from locale strings containing region identifiers to ensure proper translation mapping (e.g., `es-ES` will now correctly map to `es` translations).

### Additional Changes
- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables
<!--
Provide links to the files with corresponding changes.
Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->

## Motivation and Context
<!--
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.
If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless it is an obvious bug or documentation fix
that will have little conversation).
-->
This PR fixes issue #7981 where the translation system fails to properly handle locale codes with region identifiers in the `Accept-Language` header.

When users send requests with headers like `Accept-Language: es-ES`, the system was using the full string (`es-ES`) for translation lookup instead of extracting the base language code (`es`). This caused Spanish translations to default to English because no exact match for `es-ES` was found in the translation data.

By parsing the locale string and extracting just the language part, we ensure that users receive translations in their requested language regardless of whether they include region information.

## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
<details>
    <summary>1. Create a payment link with es-ES in Accept-Language header</summary>

cURL

    curl --location --request POST 'http://localhost:8080/payments' \
        --header 'Content-Type: application/json' \
        --header 'Accept: application/json' \
        --header 'Accept-Language: es-ES' \
        --header 'api-key: dev_tizBo0XFMZBNZ3jWBlkrc6C81CiCdliXrLXFoAg2fTgoTmKvOIk2oAP43Gwb3AGK' \
        --data-raw '{"customer_id":"cus_Wz8ND2QMGUTQCZBgO4Jx_1","profile_id":"pro_DC4DZ899zblYKajNmd0K","customer_acceptance":{"acceptance_type":"online","accepted_at":"1963-05-03T04:07:52.723Z","online":{"ip_address":"127.0.0.1","user_agent":"amet irure esse"}},"amount":10,"currency":"EUR","confirm":false,"payment_link":true,"setup_future_usage":"off_session","capture_method":"automatic","billing":{"address":{},"email":"random@juspay.in"},"return_url":"https://example.com","payment_link_config":{"theme":"#111111","background_image":{"url":"https://img.freepik.com/free-photo/abstract-blue-geometric-shapes-background_24972-1841.jpg","position":"bottom","size":"cover"}}}'

Response

    {"payment_id":"pay_zjyjvsTOPQKx0sYDzkzq","merchant_id":"merchant_1746522436","status":"requires_payment_method","amount":10,"net_amount":10,"shipping_cost":null,"amount_capturable":0,"amount_received":null,"connector":null,"client_secret":"pay_zjyjvsTOPQKx0sYDzkzq_secret_hD6KQpqlkWdk9wTPPDIB","created":"2025-05-09T08:09:43.323Z","currency":"EUR","customer_id":"cus_Wz8ND2QMGUTQCZBgO4Jx_1","customer":{"id":"cus_Wz8ND2QMGUTQCZBgO4Jx_1","name":null,"email":null,"phone":null,"phone_country_code":null},"description":null,"refunds":null,"disputes":null,"mandate_id":null,"mandate_data":null,"setup_future_usage":"off_session","off_session":null,"capture_on":null,"capture_method":"automatic","payment_method":null,"payment_method_data":null,"payment_token":null,"shipping":null,"billing":{"address":null,"phone":null,"email":"random@juspay.in"},"order_details":null,"email":null,"name":null,"phone":null,"return_url":"https://example.com/","authentication_type":null,"statement_descriptor_name":null,"statement_descriptor_suffix":null,"next_action":null,"cancellation_reason":null,"error_code":null,"error_message":null,"unified_code":null,"unified_message":null,"payment_experience":null,"payment_method_type":null,"connector_label":null,"business_country":null,"business_label":"default","business_sub_label":null,"allowed_payment_method_types":null,"ephemeral_key":{"customer_id":"cus_Wz8ND2QMGUTQCZBgO4Jx_1","created_at":1746778183,"expires":1746781783,"secret":"epk_f853d34ab7444310b3a54b0704e34867"},"manual_retry_allowed":null,"connector_transaction_id":null,"frm_message":null,"metadata":null,"connector_metadata":null,"feature_metadata":null,"reference_id":null,"payment_link":{"link":"http://localhost:8080/payment_link/merchant_1746522436/pay_zjyjvsTOPQKx0sYDzkzq?locale=es-ES","secure_link":null,"payment_link_id":"plink_FAtpjPaeg4T5UjMsVBeg"},"profile_id":"pro_DC4DZ899zblYKajNmd0K","surcharge_details":null,"attempt_count":1,"merchant_decision":null,"merchant_connector_id":null,"incremental_authorization_allowed":null,"authorization_count":null,"incremental_authorizations":null,"external_authentication_details":null,"external_3ds_authentication_attempted":false,"expires_on":"2025-05-09T08:24:43.318Z","fingerprint":null,"browser_info":null,"payment_method_id":null,"payment_method_status":null,"updated":"2025-05-09T08:09:43.343Z","split_payments":null,"frm_metadata":null,"extended_authorization_applied":null,"capture_before":null,"merchant_order_reference_id":null,"order_tax_amount":null,"connector_mandate_id":null,"card_discovery":null,"force_3ds_challenge":false,"force_3ds_challenge_trigger":false,"issuer_error_code":null,"issuer_error_message":null}

<img width="1509" alt="Screenshot 2025-05-09 at 1 51 02 PM" src="https://github.com/user-attachments/assets/f70bbdfe-d375-4b1b-a1c5-53ed012adfab" />

</details>

<details>
    <summary>2. Create a payout link</summary>

cURL

    curl --location --request POST 'http://localhost:8080/payouts/create' \
        --header 'Content-Type: application/json' \
        --header 'api-key: dev_tizBo0XFMZBNZ3jWBlkrc6C81CiCdliXrLXFoAg2fTgoTmKvOIk2oAP43Gwb3AGK' \
        --data '{"amount":1,"currency":"EUR","customer_id":"cus_Wz8ND2QMGUTQCZBgO4Jx","description":"Its my first payout request","entity_type":"Individual","confirm":false,"auto_fulfill":true,"session_expiry":1000000,"priority":"instant","profile_id":"pro_DC4DZ899zblYKajNmd0K","payout_link":true,"return_url":"https://www.google.com","payout_link_config":{"form_layout":"journey","theme":"#0066ff","logo":"https://hyperswitch.io/favicon.ico","merchant_name":"HyperSwitch Inc.","test_mode":true}}'

Response

    {"payout_id":"93d4cfee-cfcd-4be0-b750-049c98a1f220","merchant_id":"merchant_1746522436","amount":1,"currency":"EUR","connector":null,"payout_type":null,"payout_method_data":null,"billing":null,"auto_fulfill":true,"customer_id":"cus_Wz8ND2QMGUTQCZBgO4Jx","customer":{"id":"cus_Wz8ND2QMGUTQCZBgO4Jx","name":null,"email":"abc@example.com","phone":null,"phone_country_code":null},"client_secret":"payout_93d4cfee-cfcd-4be0-b750-049c98a1f220_secret_UllSmh3B4jG5IMkov2ft","return_url":"https://www.google.com","business_country":null,"business_label":null,"description":"Its my first payout request","entity_type":"Individual","recurring":false,"metadata":{},"merchant_connector_id":null,"status":"requires_payout_method_data","error_message":null,"error_code":null,"profile_id":"pro_DC4DZ899zblYKajNmd0K","created":"2025-05-09T08:11:21.214Z","connector_transaction_id":null,"priority":"instant","payout_link":{"payout_link_id":"payout_link_DkmRGHGOrm12ZZRvYH5o","link":"http://localhost:8080/payout_link/merchant_1746522436/93d4cfee-cfcd-4be0-b750-049c98a1f220?locale=en"},"email":"abc@example.com","name":null,"phone":null,"phone_country_code":null,"unified_code":null,"unified_message":null,"payout_method_id":null}

<img width="1505" alt="Screenshot 2025-05-09 at 1 50 16 PM" src="https://github.com/user-attachments/assets/4f85519e-50b4-407a-9be9-9498b1b8f09d" />


</details>

## Checklist
<!-- Put an `x` in the boxes that apply -->
- [x] I formatted the code `cargo +nightly fmt --all`
- [x] I addressed lints thrown by `cargo clippy`
- [x] I reviewed the submitted code
- [x] I added unit tests for my changes where possible