2021-04-11 14:55:53 +00:00
|
|
|
|
+++
|
|
|
|
|
title = "Translating Web-UI"
|
|
|
|
|
weight = 10
|
|
|
|
|
+++
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Help with translating the web-ui is greatly appreciated. I can only
|
|
|
|
|
provide translations for English and German, and these may be wrong -
|
|
|
|
|
so pointing out mistakes is also appreciated :).
|
|
|
|
|
|
|
|
|
|
Here is a detailed walkthrough for adding a new language. It requires
|
|
|
|
|
to code in [Elm](https://elm-lang.org). But even if you're not a
|
|
|
|
|
programmer, you will be comfortable as it's not difficult for this
|
|
|
|
|
task. Elm is also a nice and friendly language, provding helpful error
|
|
|
|
|
messages.
|
|
|
|
|
|
|
|
|
|
This guide assumes no knowledge about Elm at all.
|
|
|
|
|
|
|
|
|
|
# TL;DR
|
|
|
|
|
|
|
|
|
|
If you are already familiar with Elm, here is the TL;DR:
|
|
|
|
|
|
|
|
|
|
1. Goto `Messages.UiLanguage` in `modules/webapp/src/main/elm` and add
|
|
|
|
|
another language to the union type and also to the `all` list.
|
|
|
|
|
2. Fix all compile errors by providing a different `Texts` value for
|
|
|
|
|
the new language.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Prepare
|
|
|
|
|
|
|
|
|
|
You need to install [git](https://git-scm.org),
|
|
|
|
|
[sbt](https://scala-sbt.org), [Elm](https://elm-lang.org) and
|
|
|
|
|
[nodejs](https://www.npmjs.com/get-npm) (for the `npm` command) to
|
|
|
|
|
compile and run the project.
|
|
|
|
|
|
|
|
|
|
It is also recommended to install `elm-format` as it will help you to
|
|
|
|
|
format the elm source code. Look
|
|
|
|
|
[here](https://github.com/avh4/elm-format) for how to install it with
|
|
|
|
|
your editor of choice.
|
|
|
|
|
|
|
|
|
|
## Checkout the source code
|
|
|
|
|
|
|
|
|
|
Note: These steps are only required to do once. If you come back to
|
|
|
|
|
translating, just start the application.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Use git to clone the docspell repository to your machine. In a
|
|
|
|
|
terminal type:
|
|
|
|
|
|
|
|
|
|
``` bash
|
|
|
|
|
❯ git clone https://github.com/eikek/docspell.git
|
|
|
|
|
Cloning into 'docspell'...
|
|
|
|
|
remote: Enumerating objects: 1861, done.
|
|
|
|
|
remote: Counting objects: 100% (1861/1861), done.
|
|
|
|
|
remote: Compressing objects: 100% (861/861), done.
|
|
|
|
|
remote: Total 30276 (delta 821), reused 1604 (delta 668), pack-reused 28415
|
|
|
|
|
Receiving objects: 100% (30276/30276), 60.89 MiB | 23.62 MiB/s, done.
|
|
|
|
|
Resolving deltas: 100% (14658/14658), done.
|
|
|
|
|
|
|
|
|
|
/tmp took 4s
|
|
|
|
|
❯
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This creates a new directory `docspell`. Change into it, create a
|
|
|
|
|
`DOCSPELL_ENV` environment variable and run sbt:
|
|
|
|
|
|
|
|
|
|
``` bash
|
|
|
|
|
❯ cd docspell
|
|
|
|
|
docspell on master via 🌳 v0.19.1 via ☕ v11.0.9 via ⬢ v12.21.0
|
|
|
|
|
❯ export DOCSPELL_ENV=dev
|
|
|
|
|
❯ sbt
|
|
|
|
|
[info] welcome to sbt 1.5.0 (Oracle Corporation Java 1.8.0_212)
|
|
|
|
|
[info] loading settings for project global-plugins from plugins.sbt ...
|
|
|
|
|
[info] loading settings for project docspell-build from plugins.sbt ...
|
|
|
|
|
[info] loading project definition from /tmp/docspell/project
|
|
|
|
|
[info] compiling 6 Scala sources to /tmp/docspell/project/target/scala-2.12/sbt-1.0/classes ...
|
|
|
|
|
[info] loading settings for project root from build.sbt,version.sbt ...
|
|
|
|
|
[info] resolving key references (24191 settings) ...
|
|
|
|
|
[info] set current project to docspell-root (in build file:/tmp/docspell/)
|
|
|
|
|
[info] sbt server started at local:///home/eike/.sbt/1.0/server/3cf61b9ad9af43ee6032/sock
|
|
|
|
|
[info] started sbt server
|
|
|
|
|
sbt:docspell-root>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This downloads some stuff and puts you in the sbt shell. Now compile
|
|
|
|
|
everything (only needed the first time after checkout):
|
|
|
|
|
|
|
|
|
|
``` sbt
|
|
|
|
|
sbt:docspell-root> make
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This will take a while, you need to wait until this is finished.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Start the application
|
|
|
|
|
|
|
|
|
|
If sbt is not started, start sbt from within the source root. Also
|
|
|
|
|
export the `DOCSPELL_ENV` variable *before* starting sbt:
|
|
|
|
|
|
|
|
|
|
``` bash
|
|
|
|
|
> export DOCSPELL_ENV=dev
|
|
|
|
|
> sbt
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Then start the application:
|
|
|
|
|
|
|
|
|
|
``` sbt
|
|
|
|
|
sbt:docspell-root> reStart
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This starts docspell (joex and the restserver). Once the output gets a
|
|
|
|
|
bit quiter, open a browser and navigate to `http://localhost:7880`.
|
|
|
|
|
You can create a new account (if not already done so) and login.
|
|
|
|
|
|
|
|
|
|
Note that the database is created in your `/tmp` directory, so it
|
|
|
|
|
might be cleared once you restart your machine. For translating this
|
|
|
|
|
should not be a problem.
|
|
|
|
|
|
|
|
|
|
## Make webui updates faster
|
|
|
|
|
|
|
|
|
|
The sbt build tool could be used to watch the elm sources and
|
|
|
|
|
re-compile everything on change. This however also restarts the server
|
|
|
|
|
and takes quite long. When only coding on the webui the server can be
|
|
|
|
|
just left as is. Only the new compiled webapp must be made available
|
|
|
|
|
to the running server. For this, a script is provided in the
|
|
|
|
|
`project/` folder.
|
|
|
|
|
|
2021-12-20 22:03:05 +00:00
|
|
|
|
Now open two more terminals and `cd` into the docspell folder as before
|
|
|
|
|
and run the following in one:
|
2021-04-11 14:55:53 +00:00
|
|
|
|
|
|
|
|
|
``` bash
|
2021-12-20 22:03:05 +00:00
|
|
|
|
❯ ./project/dev-ui-build.sh watch-js
|
2021-04-11 14:55:53 +00:00
|
|
|
|
Compile elm to js …
|
|
|
|
|
Success!
|
|
|
|
|
|
|
|
|
|
Main ───> /tmp/docspell/modules/webapp/target/scala-2.13/classes/META-INF/resources/webjars/docspell-webapp/0.22.0-SNAPSHOT/docspell-app.js
|
|
|
|
|
|
2021-12-20 22:03:05 +00:00
|
|
|
|
Watching elm sources. C-c to quit.
|
2021-04-11 14:55:53 +00:00
|
|
|
|
Setting up watches. Beware: since -r was given, this may take a while!
|
|
|
|
|
Watches established.
|
|
|
|
|
```
|
|
|
|
|
|
2021-12-20 22:03:05 +00:00
|
|
|
|
And in the other run this:
|
|
|
|
|
|
|
|
|
|
``` bash
|
|
|
|
|
❯ ./project/dev-ui-build.sh watch-css
|
|
|
|
|
Watching css …
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Once you have this, you're all set. The docspell application is
|
|
|
|
|
running and changes to elm and css files are detected, the webapp is
|
|
|
|
|
compiled and the resulting javascript and css file is copied to the
|
|
|
|
|
correct location. To see your changes, a refresh in the browser is
|
|
|
|
|
necessary.
|
2021-04-11 14:55:53 +00:00
|
|
|
|
|
|
|
|
|
If this script is not working, install inotify-tools. The
|
|
|
|
|
`inotifywait` command is required.
|
|
|
|
|
|
2021-12-20 22:03:05 +00:00
|
|
|
|
You'll notice that compiling elm and css is very fast.
|
2021-04-11 14:55:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Find the webapp sources
|
|
|
|
|
|
|
|
|
|
The web-ui is implemented in the `webapp` module. The sources can be
|
|
|
|
|
found in the folder `modules/webapp/src/main/elm`.
|
|
|
|
|
|
|
|
|
|
All translated strings are in the files below `Messages` directory.
|
|
|
|
|
You should start with the file `UiLanguage.elm` to add a new language
|
|
|
|
|
to the list. Then start with `App.elm` to provide transalations. See
|
|
|
|
|
below for details.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Example: Add German
|
|
|
|
|
|
|
|
|
|
## Add the new language
|
|
|
|
|
|
|
|
|
|
Start by editing `UiLanguage.elm` and add another language to the
|
|
|
|
|
list:
|
|
|
|
|
|
|
|
|
|
``` elm
|
|
|
|
|
type UiLanguage
|
|
|
|
|
= English
|
|
|
|
|
| German
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
More languaes are simply appended using the `|` symbol. Use the
|
|
|
|
|
English name here, because this is source code.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Also add it to the list of all languages below. Simply add the new
|
|
|
|
|
language separated by a comma `,`.
|
|
|
|
|
|
|
|
|
|
``` elm
|
|
|
|
|
all : List UiLanguage
|
|
|
|
|
all =
|
|
|
|
|
[ English
|
|
|
|
|
, German
|
|
|
|
|
]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
If you make a mistake, the elm compiler will tell you with usually
|
|
|
|
|
quite helpful messages. Now, after adding this, there will be errors
|
|
|
|
|
when compiling the elm files. You should see something like this:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
Detected problems in 1 module.
|
|
|
|
|
-- MISSING PATTERNS ------------------- modules/webapp/src/main/elm/Messages.elm
|
|
|
|
|
|
|
|
|
|
This `case` does not have branches for all possibilities:
|
|
|
|
|
|
|
|
|
|
45|> case lang of
|
|
|
|
|
46|> English ->
|
|
|
|
|
47|> gb
|
|
|
|
|
|
|
|
|
|
Missing possibilities include:
|
|
|
|
|
|
|
|
|
|
German
|
|
|
|
|
|
|
|
|
|
I would have to crash if I saw one of those. Add branches for them!
|
|
|
|
|
|
|
|
|
|
Hint: If you want to write the code for each branch later, use `Debug.todo` as a
|
|
|
|
|
placeholder. Read <https://elm-lang.org/0.19.1/missing-patterns> for more
|
|
|
|
|
guidance on this workflow.
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
So around line 45 in `Messages.elm` there is something wrong. This is
|
|
|
|
|
the place where a record of all strings is returned given some
|
|
|
|
|
lanugage. Currently, there is only one set of strings for English.
|
|
|
|
|
Open this file, you see at the and a value of name `gb` for English.
|
|
|
|
|
Copy it to another name, `de` for this example (it's good practice to
|
|
|
|
|
stick to the two letter country code).
|
|
|
|
|
|
|
|
|
|
``` elm
|
|
|
|
|
de : Messages
|
|
|
|
|
de =
|
|
|
|
|
{ lang = German
|
|
|
|
|
, iso2 = "de"
|
|
|
|
|
, label = "Deutsch"
|
|
|
|
|
, flagIcon = "flag-icon flag-icon-de"
|
|
|
|
|
, app = Messages.App.gb
|
|
|
|
|
, collectiveSettings = Messages.Page.CollectiveSettings.gb
|
|
|
|
|
, login = Messages.Page.Login.gb
|
|
|
|
|
, register = Messages.Page.Register.gb
|
|
|
|
|
, newInvite = Messages.Page.NewInvite.gb
|
|
|
|
|
, upload = Messages.Page.Upload.gb
|
|
|
|
|
, itemDetail = Messages.Page.ItemDetail.gb
|
|
|
|
|
, queue = Messages.Page.Queue.gb
|
|
|
|
|
, userSettings = Messages.Page.UserSettings.gb
|
|
|
|
|
, manageData = Messages.Page.ManageData.gb
|
2022-01-26 20:20:34 +00:00
|
|
|
|
, search = Messages.Page.Search.gb
|
2021-04-11 14:55:53 +00:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Change `lang`, `iso2`, `label` and `flagIcon` appropriately. For the
|
|
|
|
|
`label` use the native language name (not English), as this is the
|
|
|
|
|
label shown to users when selecting a language. The flag icon can be
|
|
|
|
|
copied and only the last two letters need to be changed to the country
|
|
|
|
|
code. You may look [here](https://github.com/lipis/flag-icon-css) for
|
|
|
|
|
additional information.
|
|
|
|
|
|
|
|
|
|
Now the error can be fixed. Go to line 45 and add another branch to
|
|
|
|
|
the `case` expression:
|
|
|
|
|
|
|
|
|
|
``` elm
|
|
|
|
|
get : UiLanguage -> Messages
|
|
|
|
|
get lang =
|
|
|
|
|
case lang of
|
|
|
|
|
English ->
|
|
|
|
|
gb
|
|
|
|
|
|
|
|
|
|
German ->
|
|
|
|
|
de
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This makes the compiler happy again. If you refresh the browser, you
|
|
|
|
|
should see the new language in the dropdown menu. You can already
|
|
|
|
|
choose the new language, but nothing happens in the application. Of
|
|
|
|
|
course, we just copied the English strings for now. So now begins the
|
|
|
|
|
translation process.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Translating
|
|
|
|
|
|
|
|
|
|
Now translation can begin. If you look at the newly created value
|
|
|
|
|
`de`, you'll see some entries in the record. Each corresponds to a
|
|
|
|
|
page: `login` is for the login page, `home` for the "home page" etc;
|
|
|
|
|
and `app` is for the top menu.
|
|
|
|
|
|
|
|
|
|
Take one of them and start translating. For the example, I use the
|
|
|
|
|
first one which is `Messages.App`. The file to this is
|
|
|
|
|
`Messages/App.em`. You can always replace the dots with slashes to
|
|
|
|
|
find a file to an elm module. Open this file and you'll see again a
|
|
|
|
|
`gb` value at the end. Copy it to `de` and start translating:
|
|
|
|
|
|
|
|
|
|
``` elm
|
|
|
|
|
de : Texts
|
|
|
|
|
de =
|
|
|
|
|
{ collectiveProfile = "Kollektiv-Profil"
|
|
|
|
|
, userProfile = "Benutzer-Profil"
|
|
|
|
|
, lightDark = "Hell/Dunkel"
|
|
|
|
|
, logout = "Abmelden"
|
|
|
|
|
, items = "Dokumente"
|
|
|
|
|
, manageData = "Daten verwalten"
|
|
|
|
|
, uploadFiles = "Dateien hochladen"
|
|
|
|
|
, processingQueue = "Verarbeitung"
|
|
|
|
|
, newInvites = "Neue Einladung"
|
|
|
|
|
, help = "Hilfe (English)"
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Then go to the beginning of the file and add the new `de` value to the
|
|
|
|
|
list of "exposed" values. This is necessary so it can be used from
|
|
|
|
|
within the `Messages.elm` module.
|
|
|
|
|
|
|
|
|
|
``` elm
|
|
|
|
|
module Messages.App exposing
|
|
|
|
|
( Texts
|
|
|
|
|
, de {- the new value -}
|
|
|
|
|
, gb
|
|
|
|
|
)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Now you can go back to `Messages.elm` and exchange `Messages.App.gb`
|
|
|
|
|
with `Messages.App.de`.
|
|
|
|
|
|
|
|
|
|
``` elm
|
|
|
|
|
de : Messages
|
|
|
|
|
de =
|
|
|
|
|
{ lang = German
|
|
|
|
|
, iso2 = "de"
|
|
|
|
|
, label = "Deutsch"
|
|
|
|
|
, flagIcon = "flag-icon flag-icon-de"
|
|
|
|
|
, app = Messages.App.de
|
|
|
|
|
, collectiveSettings = Messages.Page.CollectiveSettings.gb
|
|
|
|
|
, login = Messages.Page.Login.gb
|
|
|
|
|
, register = Messages.Page.Register.gb
|
|
|
|
|
, newInvite = Messages.Page.NewInvite.gb
|
|
|
|
|
, upload = Messages.Page.Upload.gb
|
|
|
|
|
, itemDetail = Messages.Page.ItemDetail.gb
|
|
|
|
|
, queue = Messages.Page.Queue.gb
|
|
|
|
|
, userSettings = Messages.Page.UserSettings.gb
|
|
|
|
|
, manageData = Messages.Page.ManageData.gb
|
2022-01-26 20:20:34 +00:00
|
|
|
|
, search = Messages.Page.Search.gb
|
2021-04-11 14:55:53 +00:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
If you refresh the browser, you should now see the new values. Then
|
|
|
|
|
take the next entry and start over. It happens that some files contain
|
|
|
|
|
other string-sets of certain components. Then just follow this guide
|
|
|
|
|
recursively.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Publishing
|
|
|
|
|
|
|
|
|
|
You can publish your work to this repo in various ways:
|
|
|
|
|
|
|
|
|
|
## Github PR
|
|
|
|
|
|
|
|
|
|
This is the preferred way, because it means less work for me :). If
|
|
|
|
|
you have a github account, you can create a pull request. Here is a
|
|
|
|
|
quick walk-through. There is a thorough help [at
|
|
|
|
|
github](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/proposing-changes-to-your-work-with-pull-requests).
|
|
|
|
|
|
|
|
|
|
1. Fork this repository in the github webapp
|
|
|
|
|
2. Go to the docspell source root you checked out in the terminal. Run:
|
|
|
|
|
```
|
|
|
|
|
git remote rename origin upstream
|
|
|
|
|
git remote add origin git@github.com:<your-github-name>/docspell.git
|
|
|
|
|
git fetch --all
|
|
|
|
|
```
|
|
|
|
|
3. Create a new git branch:
|
|
|
|
|
```
|
|
|
|
|
git checkout -b translate origin/master
|
|
|
|
|
```
|
|
|
|
|
4. Make a commit of your changes:
|
|
|
|
|
```
|
|
|
|
|
git config user.name "Your Name"
|
|
|
|
|
git config user.email "Your Email" #(note that this email will be publicly viewable! a dummy address is fine, too)
|
|
|
|
|
git commit -am 'Add translation for German'
|
|
|
|
|
```
|
|
|
|
|
Modify the message to your needs.
|
|
|
|
|
5. Push the change to your fork:
|
|
|
|
|
```
|
|
|
|
|
git push origin translate
|
|
|
|
|
```
|
|
|
|
|
6. Go to the github webapp and create a pull request from your branch.
|
|
|
|
|
|
|
|
|
|
## E-Mail
|
|
|
|
|
|
|
|
|
|
You can send me the patch via e-mail. You can use `git send-email` or
|
|
|
|
|
your favorite e-mail client. For this do step 4 from above and then:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
git bundle create translation.bundle origin/master..HEAD
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Then send the created `translate.bundle` file. If this command doesn't
|
|
|
|
|
work, try:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
git format-patch origin/master..HEAD
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This results in one or more `0001-…` files that you can send.
|
|
|
|
|
|
|
|
|
|
## Any other
|
|
|
|
|
|
|
|
|
|
Contact me by mail or create an issue.
|