Skip to content

[Core]: Guest URL — translation support #376

Open

Description

@wendelinux

guest url is always in english, while it should have the client's language

Expected Behavior

for example

lang("vat_id_short") should spit out BTW in dutch

Current Behavior

lang("vat_id_short") spits out VAT in dutch

Issue is in guest url for invoices and for quotes

Activity

  1. wendelinux commented on Jan 29, 2024

    @wendelinux
    Author

    after research i found out how it works, but logic is incorrect.
    when having an active session, the language of that session is beeing used.
    the guest url is clearly from guest and always should be displayed in connected client's language.
    not userlanguage from the running session

  2. nielsdrost7 commented on Jan 29, 2024

    @nielsdrost7
    Collaborator

    when having an active session, the language of that session is beeing used.
    the guest url is clearly from guest and always should be displayed in connected client's language

    Do you have an indication on where to look for the solution?
    What is your setting for match ip in your ipconfig.php?
    Is it same problem in incognito browser window?

    So admin in main browser and guest in incognito?

  3. nielsdrost7 commented on Aug 7, 2025

    @nielsdrost7
    Collaborator

    I'm moving this to the List of issues to take on for version 2.x

  4. nielsdrost7 commented on Jun 13, 2026

    @nielsdrost7
    Collaborator

    Planning Note — v2 Implementation

    Bug story: As a client receiving an invoice via the guest URL, I want the guest view to be displayed in my language (as configured on my client record), so that I see field labels like "BTW" (Dutch for VAT) instead of the English "VAT".

    v2 context: v2 uses Laravel's App::setLocale() for translations. The guest invoice/quote URL is an unauthenticated Livewire page served from the company panel. The client's locale should be read from Relation::locale (or Contact::locale) and set for the duration of that request.

    Acceptance Criteria:

    • The Relation (client) model has a locale field (e.g. nl, de, fr; falls back to the company's default locale).
    • When the guest invoice URL is loaded, the middleware (or the Livewire page's mount()) calls App::setLocale($invoice->customer->locale ?? $company->locale).
    • All trans('ip.*') calls in the guest blade render in the client's locale.
    • If the client has no locale set, falls back to the company locale, then config('app.locale').

    Implementation:

    • Add locale column (nullable, 5-char) to relations table.
    • Add locale field to the client edit form.
    • In the guest invoice Livewire page mount(): App::setLocale($this->invoice->customer->locale ?? $this->company->locale ?? config('app.locale')).
    • Ensure translation files for target locales exist under Modules/Core/Resources/lang/{locale}/.

    Test Scenarios (PHPUnit + Livewire):

    // Guest invoice view uses client locale
    /* Arrange */ $client = Relation::factory()->for($this->company)->create(['locale' => 'nl']);
                  $invoice = Invoice::factory()->for($this->company)->for($client, 'customer')->create();
    /* Act */     $response = $this->get(route('invoice.guest', ['uuid' => $invoice->uuid]));
    /* Assert */  $response->assertSee('BTW'); // Dutch translation for VAT
    // Falls back to company locale when client locale is null
    /* Arrange */ $client = Relation::factory()->for($this->company)->create(['locale' => null]);
                  $this->company->update(['locale' => 'de']);
                  $invoice = Invoice::factory()->for($this->company)->for($client, 'customer')->create();
    /* Act */     $response = $this->get(route('invoice.guest', ['uuid' => $invoice->uuid]));
    /* Assert */  $response->assertSee('MwSt'); // German translation for VAT

    Generated by Claude Code

  5. changed the title [-]translations in guest url[/-] [+][Core]: Guest URL — translation support[/+] on Jun 13, 2026
  6. added this to the v2.0.0-alpha milestone on Jun 13, 2026
  7. nielsdrost7 commented on Jul 16, 2026

    @nielsdrost7
    Collaborator

    Test Suggestions

    Added to support future implementation of this request. The issue body is unchanged.

    There is no guest-facing invoice/quote URL in v2 today: Modules/Invoices/routes/web.php and Modules/Quotes/routes/web.php are both empty (just <?php), so there's no route to reproduce the reported bug against yet. The only related code is a dormant legacy class, Modules\Core\Support\HTML (HTML::invoice() / HTML::quote()), which does call app()->setLocale($invoice->customer->language) / app()->setLocale($quote->customer->language) — so locale-switching intent exists — but it's unused anywhere (no controller calls it) and references relations/properties that don't match the current models ($invoice->companyProfile — Invoice only has company(), not companyProfile() — and invoice_templates.*/templates.invoices.default Blade views that don't exist in Modules/Invoices/resources/views, which only has .gitkeep). Modules\Clients\Models\Relation does have a language column, so the data this needs is present on the client. This issue can't be reproduced against current code; it describes the desired behaviour for guest routes that need to be built first.

    • PHPUnit: it_sets_the_app_locale_from_the_clients_language_when_rendering_a_guest_invoice()
    #[Test]
    public function it_sets_the_app_locale_from_the_clients_language_when_rendering_a_guest_invoice(): void
    {
        /* Arrange */
        $client  = Relation::factory()->for($this->company)->create(['language' => 'nl']);
        $invoice = Invoice::factory()->for($this->company)->create(['customer_id' => $client->id]);
    
        /* Act */
        $this->get(route('invoices.guest.show', ['url_key' => $invoice->url_key]));
    
        /* Assert */
        $this->assertSame('nl', app()->getLocale());
    }
    • PHPUnit: it_translates_vat_id_short_using_the_clients_language_not_the_app_default()
    #[Test]
    public function it_translates_vat_id_short_using_the_clients_language_not_the_app_default(): void
    {
        /* Arrange */
        app()->setLocale('en');
        $client  = Relation::factory()->for($this->company)->create(['language' => 'nl']);
        $invoice = Invoice::factory()->for($this->company)->create(['customer_id' => $client->id]);
    
        /* Act */
        $response = $this->get(route('invoices.guest.show', ['url_key' => $invoice->url_key]));
    
        /* Assert */
        $response->assertSee('BTW')->assertDontSee('VAT');
    }
    • PHPUnit: it_falls_back_to_the_company_default_language_when_the_client_has_none_set()
    #[Test]
    public function it_falls_back_to_the_company_default_language_when_the_client_has_none_set(): void
    {
        /* Arrange */
        $client  = Relation::factory()->for($this->company)->create(['language' => null]);
        $invoice = Invoice::factory()->for($this->company)->create(['customer_id' => $client->id]);
    
        /* Act */
        $this->get(route('invoices.guest.show', ['url_key' => $invoice->url_key]));
    
        /* Assert */
        $this->assertSame(app()->getLocale(), app()->getLocale());
    }

    Edge cases worth covering: the guest quote view has the same gap as the guest invoice view and should be fixed together (both routes are currently unbuilt); and restoring the app locale after the guest request finishes, so a subsequent authenticated request in the same process/queue worker isn't left on the client's language.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

refinedRefined with SMART plan / test suggestions

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions