GithubHelp home page GithubHelp logo

[Request] RTL support about invoiceninja HOT 21 OPEN

Zontex avatar Zontex commented on September 25, 2024
[Request] RTL support

from invoiceninja.

Comments (21)

turbo124 avatar turbo124 commented on September 25, 2024 1

@Zontex

I'm not sure this could be executed, The best solution for this would be to create a client/group setting for your RTL clients and set your RTL design as the default design for those clients.

from invoiceninja.

turbo124 avatar turbo124 commented on September 25, 2024 1

@Zontex we manage our translations here, you can join up and adjust the translations as necessary

https://transifex.com

from invoiceninja.

turbo124 avatar turbo124 commented on September 25, 2024

@Zontex if you are referring to the PDF's and RTL support, you would need to use css helpers which would enable this.

Within the UI of the application rtl is not supported.

from invoiceninja.

Zontex avatar Zontex commented on September 25, 2024

@Zontex if you are referring to the PDF's and RTL support, you would need to use css helpers which would enable this.

Within the UI of the application rtl is not supported.

Hi thanks for your reply, yes this is exactly what I mean. is there any instructions available on how to do so?

from invoiceninja.

turbo124 avatar turbo124 commented on September 25, 2024

@Zontex

these types of CSS properties are available:

p.rtl {
direction: rtl;
}

from invoiceninja.

Zontex avatar Zontex commented on September 25, 2024

@Zontex

these types of CSS properties are available:

p.rtl { direction: rtl; }

Got you, thank you so much for the quick response! any plan to make it integrated option? once changed to RTL language such as Arabic/Hebrew it will automatically change the PDF/UI view?

from invoiceninja.

Zontex avatar Zontex commented on September 25, 2024

I changed the invoice successfully to this CSS:

<style id="style">
    @import url($font_url);

    :root {
        --primary-color: $primary_color;
        --secondary-color: $secondary_color;
        --line-height: 1.6;
    }

    html {
        width: 210mm;
        height: 200mm;     
    }

    body {
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
        font-family: $font_name, Helvetica, sans-serif;
        font-size: $font_size !important;
        zoom: 80%;
        direction: rtl; /* Added for RTL */
        text-align: right; /* Added for RTL */
    }

    table tr td, table tr, th {
        font-size: $font_size !important;
    }

    @page {
        margin-left: $global_margin;
        margin-right: $global_margin;
        margin-top: 5;
        margin-bottom: 5;
        size: $page_size $page_layout;
    }

    p {
        margin: 0;
        padding: 0;
    }
    
    p.rtl{
        direction: rtl;
        text-align: right;
    }
    
    #qr-bill {
        width: 100% !important;
        box-sizing: border-box;
        border-collapse: collapse;
        color: #000;
    }

    #qr-bill td {
        max-width: none;
    }

    .header-container {
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;
        gap: 20px;
    }

    .company-logo-container {
        display: inline-block;
    }

    .company-logo {
        max-width: $company_logo_size;
    }

    #company-details {
        display: flex;
        flex-direction: column;
        line-height: var(--line-height);
        text-align: right; /* Added for RTL */
    }

    #company-details > p:first-child {
        color: var(--primary-color);
    }

    #company-address {
        display: flex;
        flex-direction: column;
        line-height: var(--line-height);
        text-align: right; /* Added for RTL */
    }

    .entity-label {
        margin-top: 2.5rem;
        text-transform: uppercase;
        padding-right: 1rem; /* Changed padding for RTL */
        margin-bottom: 1rem;
        font-weight: bold;
        color: var(--primary-color);
    }

    .client-and-entity-wrapper {
        padding: 1rem;
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;
        border-top: 1px solid #d8d8d8;
        border-bottom: 1px solid #d8d8d8;
    }

    #entity-details {
        display: flex;
        text-align: right; /* Changed text alignment for RTL */
        margin-left: 20px; /* Changed margin for RTL */
        line-height: var(--line-height) !important;
    }

    #entity-details > tr,
    #entity-details th {
        font-weight: normal;
        padding-left: 15px; /* Changed padding for RTL */
        line-height: var(--line-height) !important;
    }

    #client-details {
        display: flex;
        flex-direction: column;
        line-height: var(--line-height);
        padding-left: 30px; /* Changed padding for RTL */
    }

    #client-details > :first-child {
        font-weight: bold;
    }

    #shipping-details {
        display: $show_shipping_address;
        flex-direction: column;
        line-height: var(--line-height);
    }

    [data-ref="table"] {
        margin-top: 1rem;
        margin-bottom: 5px;
        min-width: 100%;
        table-layout: fixed;
        overflow-wrap: break-word;
    }

    .task-time-details {
        display: block;
        margin-top: 5px;
        color: grey;
    }

    [data-ref="table"] > thead {
        text-align: right; /* Changed text alignment for RTL */
    }

    [data-ref="table"] > thead > tr > th {
        font-size: 1.1rem;
        padding-bottom: 1.5rem;
        padding-right: 1rem; /* Changed padding for RTL */
    }

    [data-ref="table"] > tbody > tr > td {
        border-top: 1px solid #d8d8d8;
        border-bottom: 1px solid #d8d8d8;
        padding: 1rem 1rem;
    }

    [data-ref="table"] > tbody > tr > td:first-child {
        color: var(--primary-color);
    }

    [data-ref="table"] > thead > tr > th:last-child,
    [data-ref="table"] > tbody > tr > td:last-child {
        text-align: left; /* Changed text alignment for RTL */
    }

    [data-ref="table"] > thead > tr > th:last-child {
        padding-left: 1rem; /* Changed padding for RTL */
    }

    [data-ref="table"] > tbody > tr:nth-child(odd) {
        background-color: #f5f5f5;
    }

    #table-totals {
        margin-top: 0rem;
        display: grid;
        grid-template-columns: 2fr 1fr;
        padding-top: 0rem;
        padding-right: 1rem;
        padding-left: 1rem;
        gap: 80px;
        page-break-inside: avoid;
        overflow: visible !important;
        text-align: right; /* Added for RTL */
    }

    #table-totals .totals-table-right-side > * {
        display: grid;
        grid-template-columns: 1fr 1fr;
    }

    #table-totals>.totals-table-right-side>*> :nth-child(1) {
        text-align: right; /* Changed text alignment for RTL */
        margin-top: .75rem;
    }

    #table-totals>.totals-table-right-side>*> :nth-child(2) {
        text-align: left; /* Changed text alignment for RTL */
    }

    #table-totals>.totals-table-right-side> * > :not([hidden]) ~ :not([hidden]) {
        --tw-space-y-reverse: 0;
        margin-top: calc(.75rem * calc(1 - var(--tw-space-y-reverse)));
        margin-bottom: calc(.75rem * var(--tw-space-y-reverse));
    }

    #table-totals
    > *
    [data-element='product-table-balance-due-label'],
    #table-totals
    > *
    [data-element='product-table-balance-due'] {
        font-weight: bold;
    }

    #table-totals
    > *
    [data-element='product-table-balance-due'] {
        color: var(--primary-color);
    }

    #table-totals > * > :last-child {
        text-align: left; /* Changed text alignment for RTL */
        padding-left: 0.5rem; /* Changed padding for RTL */
    }

    #footer {
        margin-top: 10px;
        margin-right: 1rem; /* Changed margin for RTL */
        text-align: right; /* Added for RTL */
    }

    /** Markdown-specific styles. **/
    #product-table h3,
    #task-table h3,
    #delivery-note-table h3 {
        font-size: 1rem;
        margin-bottom: 0;
    }

    [data-ref="total_table-public_notes"] {
        margin-top: 1rem;
    }

    [data-ref="statement-totals"] {
        margin-top: 1rem;
        text-align: right;
        margin-right: .75rem;
    }
    
    [data-ref*=".line_total-td"] {
        white-space: nowrap;
    }

    /** .repeating-header,
    .repeating-header-space, **/
    .repeating-footer,
    .repeating-footer-space {
        height: 10px;
    }
    .repeating-header {
        position: fixed;
        top: 0;
    }
    .repeating-footer {
        position: fixed;
        bottom: 0;
    }

    [data-element='product_table-product.description-td'], td {
        min-width: 100%;
        max-width: 300px;
        overflow-wrap: break-word; 
    }
    
    .stamp {
        transform: rotate(12deg);
        color: #555;
        font-size: 3rem;
        font-weight: 700;
        border: 0.25rem solid #555;
        display: inline-block;
        padding: 0.25rem 1rem;
        text-transform: uppercase;
        border-radius: 1rem;
        font-family: 'Courier';
        mix-blend-mode: multiply;
        z-index: 200 !important;
        position: fixed;
        text-align: center;
        float: right;
    }

    .is-paid {
        color:  #D23;
        border: 1rem double  #D23;
        transform: rotate(-5deg);
        font-size: 6rem;
        font-family: "Open sans", Helvetica, Arial, sans-serif;
        border-radius: 0;
        padding: 0.5rem;
        opacity: 0.2;
        z-index: 200 !important;
        position: fixed;
        display: $show_paid_stamp;
    } 

    .project-header {
        font-size: 1.2em;
        margin-top: 0.1em;
        margin-bottom: 0;
        padding-bottom: 0;
        margin-left: 0;
        margin-right: 0;
        font-weight: bold;
        color: #505050;
    } 

    .pqrcode {
        
    }
        
    /** Useful snippets, uncomment to enable. **/

    /** Hide company logo **/
    /* .company-logo { display: none } */

    /* Hide company details */
    /* #company-details > * { display: none } */

    /* Hide company address */
    /* #company-address > * { display: none } */

    /* Hide public notes */
    /* [data-ref="total_table-public_notes"] { display: none } */

    /* Hide terms label */
    /* [data-ref="total_table-terms-label"] { display: none } */

    /* Hide totals table */
    /* #table-totals { display: none } */

    /* Hide totals table left side */
    /* #table-totals div:first-child > * { display: none !important } */

    /* Hide totals table right side */
    /* .totals-table-right-side { display: none } */

    /** For more info, please check our docs: https://invoiceninja.github.io **/
    /** To find out selectors on your own: https://invoiceninja.github.io/docs/custom-fields/#snippets **/
</style>

But I still haven't figured out how to RTL the entire UI. when I do RTL on the body, it breaks the UI. any suggestion?

from invoiceninja.

turbo124 avatar turbo124 commented on September 25, 2024

@Zontex

RTL is super tricky, and it is not something I am familiar with at all.

For this to be supported, the invoice designs would need to be customized to suit with the correct CSS implementation.

This would be a task best suited for a user whose language is RTL, I am happy to assist however in getting the designs updated.

from invoiceninja.

Zontex avatar Zontex commented on September 25, 2024

@Zontex

RTL is super tricky, and it is not something I am familiar with at all.

For this to be supported, the invoice designs would need to be customized to suit with the correct CSS implementation.

This would be a task best suited for a user whose language is RTL, I am happy to assist however in getting the designs updated.

I sent here the correct design for the invoice, confirmed it's working. multiple places need to update the RTL. I'm wondering if there is anyway within the framework to say something like IF hebrew then use RTL template, if not use normal template..?

from invoiceninja.

turbo124 avatar turbo124 commented on September 25, 2024

@Zontex I see your design creates a complete mirror image, including reversing the columns of the invoice table. Is this the way RTL is support to work?

from invoiceninja.

Zontex avatar Zontex commented on September 25, 2024

@Zontex

I'm not sure this could be executed, The best solution for this would be to create a client/group setting for your RTL clients and set your RTL design as the default design for those clients.

That's a brilliant idea. Then I can leave the UI in English and serve Israeli clients with RTL portal/invoicing. will dig deeper into it. I suggest to leave this ticket open, i'll get this all working and push updates perhaps others Arabic/Hebrew needs could be served with this information.

from invoiceninja.

Zontex avatar Zontex commented on September 25, 2024

@Zontex I see your design creates a complete mirror image, including reversing the columns of the invoice table. Is this the way RTL is support to work?

Yes it's exactly the way RTL work. RTL is Right-to-left, everything is the opposite. If you keep English or any other non-rtl language, it will look weird, but in RTL it looks perfect.

from invoiceninja.

Zontex avatar Zontex commented on September 25, 2024

@turbo124 There are many localization fields missing, how can I localize Hebrew? I guess as updates went, some fields hasn't been updated. would love some guidance on where to get the latest english file so I can localize it completely to Hebrew

from invoiceninja.

Zontex avatar Zontex commented on September 25, 2024

@Zontex

I'm not sure this could be executed, The best solution for this would be to create a client/group setting for your RTL clients and set your RTL design as the default design for those clients.

I just tested your advice it works completely well. I opened a group called it "israeli clients" and then created a template for each thing: portal, invoice etc... with RTL called it "invoice rtl" or "portal rtl" then assigned the template to that group.

from invoiceninja.

Zontex avatar Zontex commented on September 25, 2024

@turbo124 Quick update regarding RTL exploration:

Screenshot 2024-05-18 at 20 58 42

I managed to perfectly design the portal to RTL based on the user group using the following code:

/* Override Bootstrap for RTL */
body {
    direction: rtl;
    text-align: right;
}

.container,
.container-fluid,
.row {
    direction: rtl;
}

.col,
.col-1,
.col-2,
.col-3,
.col-4,
.col-5,
.col-6,
.col-7,
.col-8,
.col-9,
.col-10,
.col-11,
.col-12,
.col-auto,
.col-sm,
.col-sm-1,
.col-sm-2,
.col-sm-3,
.col-sm-4,
.col-sm-5,
.col-sm-6,
.col-sm-7,
.col-sm-8,
.col-sm-9,
.col-sm-10,
.col-sm-11,
.col-sm-12,
.col-sm-auto,
.col-md,
.col-md-1,
.col-md-2,
.col-md-3,
.col-md-4,
.col-md-5,
.col-md-6,
.col-md-7,
.col-md-8,
.col-md-9,
.col-md-10,
.col-md-11,
.col-md-12,
.col-md-auto,
.col-lg,
.col-lg-1,
.col-lg-2,
.col-lg-3,
.col-lg-4,
.col-lg-5,
.col-lg-6,
.col-lg-7,
.col-lg-8,
.col-lg-9,
.col-lg-10,
.col-lg-11,
.col-lg-12,
.col-lg-auto,
.col-xl,
.col-xl-1,
.col-xl-2,
.col-xl-3,
.col-xl-4,
.col-xl-5,
.col-xl-6,
.col-xl-7,
.col-xl-8,
.col-xl-9,
.col-xl-10,
.col-xl-11,
.col-xl-12,
.col-xl-auto {
    float: right;
}

.card,
.nav,
.navbar,
.modal,
.dropdown-menu,
.tooltip,
.popover {
    direction: rtl;
}

.navbar .navbar-nav {
    float: right;
}

.navbar .navbar-nav .nav-item {
    float: right;
}

.dropdown-menu {
    right: 0;
    left: auto;
}

.tooltip .arrow::before {
    border-right-color: #000;
    border-left-color: transparent;
}

.popover .arrow::before {
    border-right-color: #fff;
    border-left-color: transparent;
}

/* Additional Bootstrap component adjustments */
.form-control {
    text-align: right;
}

.input-group .input-group-text,
.input-group .form-control {
    direction: rtl;
    text-align: right;
}

.input-group-prepend,
.input-group-append {
    float: right;
}

.input-group-prepend .input-group-text,
.input-group-append .input-group-text {
    direction: rtl;
}

.modal-dialog {
    float: right;
}

.breadcrumb {
    direction: rtl;
}

.pagination {
    direction: rtl;
}

.pagination .page-link {
    direction: rtl;
}

/* Additional custom styles */
.custom-rtl {
    direction: rtl;
    text-align: right;
}

/* Ensure all custom classes with RTL are properly aligned */
.custom-rtl .row,
.custom-rtl .col,
.custom-rtl .container,
.custom-rtl .container-fluid,
.custom-rtl .card,
.custom-rtl .nav,
.custom-rtl .navbar,
.custom-rtl .modal,
.custom-rtl .dropdown-menu,
.custom-rtl .tooltip,
.custom-rtl .popover,
.custom-rtl .breadcrumb,
.custom-rtl .pagination,
.custom-rtl .form-control,
.custom-rtl .input-group,
.custom-rtl .input-group-prepend,
.custom-rtl .input-group-append,
.custom-rtl .input-group-text {
    direction: rtl;
    text-align: right;
    float: right;
}

.custom-rtl .navbar .navbar-nav {
    float: right;
}

.custom-rtl .navbar .navbar-nav .nav-item {
    float: right;
}

.custom-rtl .dropdown-menu {
    right: 0;
    left: auto;
}

.custom-rtl .tooltip .arrow::before {
    border-right-color: #000;
    border-left-color: transparent;
}

.custom-rtl .popover .arrow::before {
    border-right-color: #fff;
    border-left-color: transparent;
}

Now the last issue that seems I can't resolve is the main dashboard. if I create an account to login to Invoice ninja with RTL language by default, I dont see a place where I can inject custom CSS code into the dashboard object? in the portal by injecting the code I could fix all the portal dashboard, any chance to put a priority into adding css/javascript custom code injection on the dashboard based on a specific user / user group?

from invoiceninja.

turbo124 avatar turbo124 commented on September 25, 2024

The front end implementation would need to have the react code modified.

@beganovich is there an easy win to support RTL with the react UI?

from invoiceninja.

hillelcoren avatar hillelcoren commented on September 25, 2024

Note: the desktop/mobile app supports RTL for Arabic, I assume it can be enabled for other languages as well.

image

from invoiceninja.

Zontex avatar Zontex commented on September 25, 2024

Note: the desktop/mobile app supports RTL for Arabic, I assume it can be enabled for other languages as well.

image

Screenshot 2024-05-19 at 14 23 57

For me the desktop app still shows LTR (same as web), didn't try the mobile yet. I changed the Arabic in the desktop app also shows LTR, how does it show RTL for you? I'm using OSX desktop app

from invoiceninja.

hillelcoren avatar hillelcoren commented on September 25, 2024

That's the web app, here are links to the desktop app.

https://invoiceninja.com/apps

from invoiceninja.

Zontex avatar Zontex commented on September 25, 2024

from invoiceninja.

hillelcoren avatar hillelcoren commented on September 25, 2024

This is the macOS app, the screenshot you shared is the React web app.

https://apps.apple.com/us/app/invoice-ninja/id1503970375

from invoiceninja.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.