Help configuring properties for logo and translations

First stupid question (can’t seem to find a good manual). Where can I edit the language file? Is it a file in the webapps/openboxes?

Can’t seem to add a new locale in Openboxes self.

Second, the replacement url for the logo does not work (yet?). Is the header file editable?

First stupid question (can’t seem to find a good manual).

Not a stupid question. There’s a bunch of documentation, but it’s scattered in a few places and needs to be consolidated.

… but none of those resources address the issue you’re referring to. A few years ago I decided to use Discourse (this forum) to handle issues around missing documentation. Eventually we’ll get some help to write better docs, but for now documentation will have to live here in the forums.

Can’t seem to add a new locale in Openboxes self.

You can add a new locale by using instructions in the following post.

Note: We are planning to work on improvements to internationalization in the new year (possibly starting in March), so please let me know if you have any feedback.

Second, the replacement url for the logo does not work (yet?). Is the header file editable?

Can you explain what you tried to do?

The logo can be changed system-wide by adding the following two properties to openboxes-config.properties.

openboxes.logo.label = <URL for your logo>
openboxes.report.logo.url = <URL for your square logo>

Or you can upload a logo for each location you create.

Thanks for the follow up.

Openboxes is installed and running. Somehow I posted the wrong logfile. I stopped tomcat, cleared the log and started tomcat again. So I attached you the latest log.
catalina.docx (51.1 KB)

I’m running 10.6.5-MariaDB - MariaDB Server. MariaDB is a bit different from MySQL.Before my upgrade I was using MariaDB 5, openboxes wouldn’t install. Now it’s running, like charm (for now). I have no idea why in bootstrap is showing version 5.5 but that was before I updated my MariaDB version on the server. (Maybe tomcat keeps this version in history?). There is no other MariaDB version installed then 10.6.5

Anyway coming back to my logo question;
I added the following code to 'openboxes-config.properties:
openboxes.report.header.logo = https://www.google.com/logos/doodles/2021/new-years-eve-2021-6753651837109170-s.png
openboxes.report.header.title = Test tittle

But it’s not showing the logo / title, (after restart Tomcat).

Anyway coming back to my logo question;
I added the following code to 'openboxes-config.properties:

The following properties are ONLY for documents and reports (also note the change to the key)

openboxes.report.logo.url = https://www.google.com/logos/doodles/2021/new-years-eve-2021-6753651837109170-s.png

For the main logo, it should look like this.

openboxes.logo.url = https://www.google.com/logos/doodles/2021/new-years-eve-2021-6753651837109170-s.png
openboxes.logo.label= Test title

Any configuration property that can be customized in openboxes-config.properties (or openboxes-config.groovy) is defined in the following file. We don’t yet have documentation for all of the properties but you can use the source file as your documentation for now.

Hmm good point, do you separate the post?

Last question for now. I added in the groovy file this (so I can translate some part):

openboxes {
    tablero {
        enabled = true
        configurations {
            personal {
                name = "My Dashboard"
                filters {}
            }
            warehouse {
                name = "Warehouse Management"
                filters {}
            }
            inventory {
                name = "Inventory Management"
                filters {}
            }
            transaction {
                name = "Transaction Management"
                filters {}
            }
            fillRate {
                name = "Fill Rate"
                filters {
                    category {
                        endpoint = "/${appName}/categoryApi/list"
                    }
                }
            }
        }
        endpoints {
            number {
                inProgressPutaways {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getInProgressPutaways"
                    archived = ['inventory', 'transaction', 'fillRate']
                    order = 4
                }
                inventoryByLotAndBin {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getInventoryByLotAndBin"
                    archived = ['inventory', 'transaction', 'fillRate']
                    order = 1
                }
                inProgressShipments {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getInProgressShipments"
                    archived = ['inventory', 'transaction', 'fillRate']
                    order = 3
                }
                receivingBin {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getReceivingBin"
                    archived = ['transaction', 'fillRate']
                    order = 2
                }
                itemsInventoried {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getItemsInventoried"
                    archived = ['personal', 'warehouse', 'transaction', 'fillRate']
                    order = 5
                }
                defaultBin {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getDefaultBin"
                    archived = ['personal', 'warehouse', 'transaction', 'fillRate']
                    order = 6
                }
                negativeInventory {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getProductWithNegativeInventory"
                    archived = ['personal', 'warehouse', 'transaction', 'fillRate']
                    order = 7
                }
                expiredStock {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getExpiredProductsInStock"
                    archived = ['personal', 'warehouse', 'transaction', 'fillRate']
                    order = 8
                }
                fillRateSnapshot {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getFillRateSnapshot"
                    archived = ['personal', 'warehouse', 'inventory']
                    order = 9
                }
                openStockRequests {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getOpenStockRequests"
                    archived = ['personal', 'warehouse', 'transaction', 'fillRate']
                    order = 10
                }
                inventoryValue {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getInventoryValue"
                    archived = ['personal', 'warehouse', 'inventory', 'transaction', 'fillRate']
                    order = 11
                }
            }
            graph {
                inventorySummary {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getInventorySummary"
                    archived = ['inventory', 'transaction', 'fillRate']
                    datalabel = true
                    order = 1
                    colors {
                        labels {
                            success = ["In stock"]
                            warning = ["Above maximum", "Below reorder", "Below minimum"]
                            error = ["No longer in stock"]
                        }
                    }
                }
                expirationSummary {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getExpirationSummary"
                    archived = ['inventory', 'transaction', 'fillRate']
                    timeFilter = true
                    order = 2
                    colors {
                        datasets {
                            state6 = ["Expiration(s)"]
                        }
                        labels {
                            state5 = [
                                [code : "react.dashboard.timeline.today.label", message : "today"],
                                [code : "react.dashboard.timeline.within30Days.label", message : "within 30 days"],
                                [code : "react.dashboard.timeline.within90Days.label", message : "within 90 days"],
                                [code : "react.dashboard.timeline.within180Days.label", message : "within 180 days"],
                                [code : "react.dashboard.timeline.within360Days.label", message : "within 360 days"]
                            ]
                        }
                    }
                }
                incomingStock {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getIncomingStock"
                    archived = ['inventory', 'transaction', 'fillRate']
                    order = 3
                    colors {
                        datasets {
                            state6 = ["first"]
                            state7 = ["second"]
                            state8 = ["third"]
                        }
                    }
                }
                outgoingStock {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getOutgoingStock"
                    archived = ['inventory', 'transaction', 'fillRate']
                    order = 4
                    colors {
                        datasets {
                            success = ["first"]
                            warning = ["second"]
                            error = ["third"]
                        }
                    }
                }
                receivedStockMovements {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getReceivedStockMovements"
                    archived = ['personal', 'warehouse', 'inventory', 'fillRate']
                    timeFilter = true
                    stacked = true
                    datalabel = true
                    order = 7
                }
                discrepancy {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getDiscrepancy"
                    archived = ['inventory', 'transaction', 'fillRate']
                    timeFilter = true
                    order = 6
                }
                delayedShipments {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getDelayedShipments"
                    archived = ['transaction', 'fillRate']
                    order = 5
                    colors {
                        datasets {
                            state5 = ["first"]
                            state4 = ["second"]
                            state3 = ["third"]
                        }
                    }
                }
                sentStockMovements {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getSentStockMovements"
                    archived = ['personal', 'warehouse', 'inventory', 'fillRate']
                    timeFilter = true
                    stacked = true
                    datalabel = true
                    order = 8
                }
                lossCausedByExpiry {
                    enabled = false
                    endpoint = "/${appName}/apitablero/getLossCausedByExpiry"
                    archived = ['personal', 'warehouse', 'inventory', 'fillRate']
                    timeFilter = true
                    stacked = true
                    order = 9
                    colors {
                        datasets {
                            success = ["Inventory value not expired last day of month"]
                            warning = ["Inventory value expired last day of month"]
                            error = ["Inventory value removed due to expiry"]
                        }
                    }
                }
                productsInventoried {
                    enabled = false
                    endpoint = "/${appName}/apitablero/getProductsInventoried"
                    archived = ['personal', 'warehouse', 'transaction', 'fillRate']
                    order = 10
                    colors {
                        datasets {
                            state6 = ["first"]
                            state7 = ["second"]
                            state8 = ["third"]
                        }
                    }
                }
                percentageAdHoc {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getPercentageAdHoc"
                    archived = ['personal', 'warehouse', 'inventory', 'fillRate']
                    legend = true
                    datalabel = true
                    order = 11
                    colors {
                        labels {
                            state5 = ["STOCK"]
                            state4 = ["ADHOC"]
                        }
                    }
                }
                fillRate {
                    enabled = true
                    legend = true
                    endpoint = "/${appName}/apitablero/getFillRate"
                    archived = ['personal', 'warehouse', 'inventory']
                    timeFilter = true
                    locationFilter = true
                    timeLimit = 12
                    doubleAxeY = true
                    datalabel = false
                    size = 'big'
                    colors {
                        datasets {
                            state3 = ["Request lines submitted"]
                            state6 = ["Lines cancelled stock out"]
                            state2 = ["Average Fill Rate"]
                            state8 = ["Average of target Fill Rate"]
                        }
                    }
                    order = 12
                }
                stockOutLastMonth {
                    enabled = true
                    endpoint = "/${appName}/apitablero/getStockOutLastMonth"
                    archived = ['personal', 'warehouse', 'inventory', 'fillRate']
                    legend = true
                    datalabel = true
                    order = 13
                    colors {
                        labels {
                            success = ["Never"]
                            warning = ["Stocked out <1 week"]
                            state2  = ["Stocked out 1-2 weeks"]
                            state1  = ["Stocked out 2-3 weeks"]
                            error   = ["Stocked out 3-4 weeks"]
                        }
                    }
                }
            }
        }
    }
}

However now I get everywhere the error that indicators couldn’t be loaded :/.

I don’t have a good answer for this at the moment. Can you include explicit instructions for what you did as well as some screenshots of the error(s)?

With that said, you should not need to edit the dashboard config to translate, so I’ll ask the team if there’s a more suitable solution. If not, we’ll need to create a ticket to improve that.

Problem is that some Dashboard items are not readed from the messages.properties file but from the groovy file. Items like the menu on the left and text for the graphs (labels)

What I did was the following. I copied the following text from the openboxes-config.groovy from openboxes/Config.groovy at develop · openboxes/openboxes · GitHub

openboxes {
tablero {
enabled = true
configurations {
personal {
name = “My Dashboard”
filters {}
}
warehouse {
name = “Warehouse Management”
filters {}
}
inventory {
name = “Inventory Management”
filters {}
}
transaction {
name = “Transaction Management”
filters {}
}
fillRate {
name = “Fill Rate”
filters {
category {
endpoint = “/${appName}/categoryApi/list”
}
}
}
}
endpoints {
number {
inProgressPutaways {
enabled = true
endpoint = “/${appName}/apitablero/getInProgressPutaways”
archived = [‘inventory’, ‘transaction’, ‘fillRate’]
order = 4
}
inventoryByLotAndBin {
enabled = true
endpoint = “/${appName}/apitablero/getInventoryByLotAndBin”
archived = [‘inventory’, ‘transaction’, ‘fillRate’]
order = 1
}
inProgressShipments {
enabled = true
endpoint = “/${appName}/apitablero/getInProgressShipments”
archived = [‘inventory’, ‘transaction’, ‘fillRate’]
order = 3
}
receivingBin {
enabled = true
endpoint = “/${appName}/apitablero/getReceivingBin”
archived = [‘transaction’, ‘fillRate’]
order = 2
}
itemsInventoried {
enabled = true
endpoint = “/${appName}/apitablero/getItemsInventoried”
archived = [‘personal’, ‘warehouse’, ‘transaction’, ‘fillRate’]
order = 5
}
defaultBin {
enabled = true
endpoint = “/${appName}/apitablero/getDefaultBin”
archived = [‘personal’, ‘warehouse’, ‘transaction’, ‘fillRate’]
order = 6
}
negativeInventory {
enabled = true
endpoint = “/${appName}/apitablero/getProductWithNegativeInventory”
archived = [‘personal’, ‘warehouse’, ‘transaction’, ‘fillRate’]
order = 7
}
expiredStock {
enabled = true
endpoint = “/${appName}/apitablero/getExpiredProductsInStock”
archived = [‘personal’, ‘warehouse’, ‘transaction’, ‘fillRate’]
order = 8
}
fillRateSnapshot {
enabled = true
endpoint = “/${appName}/apitablero/getFillRateSnapshot”
archived = [‘personal’, ‘warehouse’, ‘inventory’]
order = 9
}
openStockRequests {
enabled = true
endpoint = “/${appName}/apitablero/getOpenStockRequests”
archived = [‘personal’, ‘warehouse’, ‘transaction’, ‘fillRate’]
order = 10
}
inventoryValue {
enabled = true
endpoint = “/${appName}/apitablero/getInventoryValue”
archived = [‘personal’, ‘warehouse’, ‘inventory’, ‘transaction’, ‘fillRate’]
order = 11
}
}
graph {
inventorySummary {
enabled = true
endpoint = “/${appName}/apitablero/getInventorySummary”
archived = [‘inventory’, ‘transaction’, ‘fillRate’]
datalabel = true
order = 1
colors {
labels {
success = [“In stock”]
warning = [“Above maximum”, “Below reorder”, “Below minimum”]
error = [“No longer in stock”]
}
}
}
expirationSummary {
enabled = true
endpoint = “/${appName}/apitablero/getExpirationSummary”
archived = [‘inventory’, ‘transaction’, ‘fillRate’]
timeFilter = true
order = 2
colors {
datasets {
state6 = [“Expiration(s)”]
}
labels {
state5 = [
[code : “react.dashboard.timeline.today.label”, message : “today”],
[code : “react.dashboard.timeline.within30Days.label”, message : “within 30 days”],
[code : “react.dashboard.timeline.within90Days.label”, message : “within 90 days”],
[code : “react.dashboard.timeline.within180Days.label”, message : “within 180 days”],
[code : “react.dashboard.timeline.within360Days.label”, message : “within 360 days”]
]
}
}
}
incomingStock {
enabled = true
endpoint = “/${appName}/apitablero/getIncomingStock”
archived = [‘inventory’, ‘transaction’, ‘fillRate’]
order = 3
colors {
datasets {
state6 = [“first”]
state7 = [“second”]
state8 = [“third”]
}
}
}
outgoingStock {
enabled = true
endpoint = “/${appName}/apitablero/getOutgoingStock”
archived = [‘inventory’, ‘transaction’, ‘fillRate’]
order = 4
colors {
datasets {
success = [“first”]
warning = [“second”]
error = [“third”]
}
}
}
receivedStockMovements {
enabled = true
endpoint = “/${appName}/apitablero/getReceivedStockMovements”
archived = [‘personal’, ‘warehouse’, ‘inventory’, ‘fillRate’]
timeFilter = true
stacked = true
datalabel = true
order = 7
}
discrepancy {
enabled = true
endpoint = “/${appName}/apitablero/getDiscrepancy”
archived = [‘inventory’, ‘transaction’, ‘fillRate’]
timeFilter = true
order = 6
}
delayedShipments {
enabled = true
endpoint = “/${appName}/apitablero/getDelayedShipments”
archived = [‘transaction’, ‘fillRate’]
order = 5
colors {
datasets {
state5 = [“first”]
state4 = [“second”]
state3 = [“third”]
}
}
}
sentStockMovements {
enabled = true
endpoint = “/${appName}/apitablero/getSentStockMovements”
archived = [‘personal’, ‘warehouse’, ‘inventory’, ‘fillRate’]
timeFilter = true
stacked = true
datalabel = true
order = 8
}
lossCausedByExpiry {
enabled = false
endpoint = “/${appName}/apitablero/getLossCausedByExpiry”
archived = [‘personal’, ‘warehouse’, ‘inventory’, ‘fillRate’]
timeFilter = true
stacked = true
order = 9
colors {
datasets {
success = [“Inventory value not expired last day of month”]
warning = [“Inventory value expired last day of month”]
error = [“Inventory value removed due to expiry”]
}
}
}
productsInventoried {
enabled = false
endpoint = “/${appName}/apitablero/getProductsInventoried”
archived = [‘personal’, ‘warehouse’, ‘transaction’, ‘fillRate’]
order = 10
colors {
datasets {
state6 = [“first”]
state7 = [“second”]
state8 = [“third”]
}
}
}
percentageAdHoc {
enabled = true
endpoint = “/${appName}/apitablero/getPercentageAdHoc”
archived = [‘personal’, ‘warehouse’, ‘inventory’, ‘fillRate’]
legend = true
datalabel = true
order = 11
colors {
labels {
state5 = [“STOCK”]
state4 = [“ADHOC”]
}
}
}
fillRate {
enabled = true
legend = true
endpoint = “/${appName}/apitablero/getFillRate”
archived = [‘personal’, ‘warehouse’, ‘inventory’]
timeFilter = true
locationFilter = true
timeLimit = 12
doubleAxeY = true
datalabel = false
size = ‘big’
colors {
datasets {
state3 = [“Request lines submitted”]
state6 = [“Lines cancelled stock out”]
state2 = [“Average Fill Rate”]
state8 = [“Average of target Fill Rate”]
}
}
order = 12
}
stockOutLastMonth {
enabled = true
endpoint = “/${appName}/apitablero/getStockOutLastMonth”
archived = [‘personal’, ‘warehouse’, ‘inventory’, ‘fillRate’]
legend = true
datalabel = true
order = 13
colors {
labels {
success = [“Never”]
warning = [“Stocked out <1 week”]
state2 = [“Stocked out 1-2 weeks”]
state1 = [“Stocked out 2-3 weeks”]
error = [“Stocked out 3-4 weeks”]
}
}
}
}
}
}
}

See attached screenshot :slight_smile:

I popped into another strange error. If I enter ‘enable localization mode’ and go to ‘Add Product’ (openboxes/product/create) to start translations the page keeps loading.

Log does not show anything special

2022-01-04 21:42:54,700 [http-bio-10.0.0.2-8085-exec-3] INFO filters.SecurityFilters - product.create: [user:admin, location:Centraal Magazijn Brunssum]
Create product: 37 ms
After render create.gsp for product: 38 ms
2022-01-04 21:42:54,779 [http-bio-10.0.0.2-8085-exec-3] INFO filters.SecurityFilters - Request duration for (product/create): 46ms/33ms
2022-01-04 21:42:54,823 [http-bio-10.0.0.2-8085-exec-3] INFO web.Timer - Cached request for /openboxes/grails/dashboard/megamenu.dispatch took 0:00:00.001
2022-01-04 21:42:54,842 [http-bio-10.0.0.2-8085-exec-3] INFO core.UserService - Is role ROLE_ASSISTANT in [ROLE_SUPERUSER, ROLE_ADMIN] = false
2022-01-04 21:42:54,842 [http-bio-10.0.0.2-8085-exec-3] INFO core.UserService - Is role ROLE_MANAGER in [ROLE_SUPERUSER, ROLE_ADMIN] = false
2022-01-04 21:42:54,842 [http-bio-10.0.0.2-8085-exec-3] INFO core.UserService - Is role ROLE_FINANCE in [ROLE_SUPERUSER, ROLE_ADMIN] = false
2022-01-04 21:42:54,842 [http-bio-10.0.0.2-8085-exec-3] INFO core.UserService - Is role ROLE_SUPERUSER in [ROLE_SUPERUSER, ROLE_ADMIN] = true
2022-01-04 21:42:55,121 [http-bio-10.0.0.2-8085-exec-3] INFO filters.SecurityFilters - errors.handleNotFound: [user:admin, location:Centraal Magazijn Brunssum]
2022-01-04 21:42:55,122 [http-bio-10.0.0.2-8085-exec-3] INFO core.ErrorsController - Params [action:handleNotFound, controller:errors]
2022-01-04 21:42:55,131 [http-bio-10.0.0.2-8085-exec-3] INFO filters.SecurityFilters - Request duration for (errors/handleNotFound): 1ms/9ms
2022-01-04 21:42:55,200 [http-bio-10.0.0.2-8085-exec-3] INFO web.Timer - Cached request for /openboxes/grails/dashboard/megamenu.dispatch took 0:00:00.001
2022-01-04 21:42:55,220 [http-bio-10.0.0.2-8085-exec-3] INFO core.UserService - Is role ROLE_ADMIN in [ROLE_SUPERUSER, ROLE_ADMIN] = true
2022-01-04 21:42:55,360 [http-bio-10.0.0.2-8085-exec-6] INFO filters.SecurityFilters - location.viewLogo: [user:admin, location:Centraal Magazijn Brunssum]
2022-01-04 21:42:55,362 [http-bio-10.0.0.2-8085-exec-6] INFO filters.SecurityFilters - Request duration for (location/viewLogo): 2ms/0ms

I popped into another strange error. If I enter ‘enable localization mode’ and go to ‘Add Product’ (openboxes/product/create) to start translations the page keeps loading.

This “translation” feature is very experimental and does not get tested during our normal release QA process so I imagine there are bug like this.

At the moment we don’t have plans to fix these bugs. However, we’re hoping to improve the translation process as part of project that is currently in “proposal” phase. The objective of this project is to allow the entire app will be translatable using a single translation file. But this is going to take a bit of time.

https://applications.digitalsquare.io/content/improving-openboxes-multilingual-support-and-training

What I did was the following. I copied the following text from the openboxes-config.groovy from Config.groovy

While “we should” be able to customize the dashboard this way, I have not personally tested this. A better approach for now might be to change specific config properties individually.

Again, I haven’t tested it out, but I think the following should work.

openboxes.tablero.configurations.personal.name = "Mi tablero de mandos"
openboxes.tablero.endpoints.graph.inventorySummary.colors.labels.success = "Mi tablero de mandos"
openboxes.tablero.endpoints.graph.inventorySummary.colors.labels.warning = ["Por encima del máximo", "Below reorder", "Below minimum"]

Thanks for reply.

I bypassed the error for the localization mode by looking up code and entering them manual in the database row ‘localization’. So for now I’m helped :slight_smile:

That’s a good solution.

You can also take the full messages.properties file from the source code, translate it all at once (google translate actually does an ok job here), upload that into the database and then revise the ones that are wrong. That way you’ll be starting from a decent baseline. However one caveat there is that sometimes the UI has a translation code that might not exist in messages.properties file (due to laziness) so you’ll have to hunt down some of those codes using the method you described above.

I’ve tried your code but i I use that code the graphs won’t even load. Maybe the text is hardcoded in the graphscode?

These 3 graphs for example:

Firefox_Screenshot_2022-01-17T11-53-55.240Z

If that didn’t work, then I think we’re up a creek until we refactor the dashboard to be more localizable. We’ll add this to our scope of work for our upcoming localization project.

1 Like

@David_Douma If / when you upgrade to 0.8.21 (to be released in the next week or two), I’d like to have a quick chat with you about the state of your current localization / translation. We’ve spent a lot of time working on making the application more localizable and we have a new integration feature that will make translating application strings much much easier. I’d also like to get your custom translations included in the codebase so you no longer have to manage them yourself.

No problem, i’ll wait for the update :slight_smile: glad to give you some service back!