Skip to content

Commit

Permalink
ref(i18n): update translations (#116)
Browse files Browse the repository at this point in the history
ref(i18n): update translations (#116)

ref(i18n): deploy from the deploy directory (#116)

ref(i18n): reorg task file (#116)

ref(i18n): improve task file for i18n (#116)
  • Loading branch information
plastikfan committed Apr 6, 2023
1 parent ffc797c commit 7e5d425
Show file tree
Hide file tree
Showing 15 changed files with 406 additions and 98 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ ginkgo.report

.task/

src/internal/l10n/out/translate.en-US.json
src/internal/l10n/out/active.en-US.json
src/i18n/out/en-US/active.en-GB.json

220 changes: 180 additions & 40 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,51 @@ silent: true
dotenv: [".env"]

vars:
FORMAT: json
BINARY_NAME: arcadia
TRANSLATIONS_DIR: ./src/internal/l10n/out
TRANSLATION_US: arcadia.active.en-US.json
DEPLOY_DIR: ./src/i18n/deploy
OUT_DIR: ./src/i18n/out
DIST_DIR: dist
#
SOURCE_LANG: en-GB
SOURCE_ACTIVE: "active.{{.SOURCE_LANG}}.{{.FORMAT}}"
SOURCE_ACTIVE_FILE: "{{.OUT_DIR}}/active.{{.SOURCE_LANG}}.{{.FORMAT}}"
DEFAULT_ACTIVE: "{{.BINARY_NAME}}.{{.SOURCE_ACTIVE}}"
DEFAULT_ACTIVE_FILE: "{{.OUT_DIR}}/{{.DEFAULT_ACTIVE}}"
EXTRACT_ACTIVE: "active.{{.SOURCE_LANG}}.{{.FORMAT}}"
EXTRACT_NAME: active.{{.SOURCE_LANG}}.{{.FORMAT}}
#
LANGUAGE_US: en-US
US_OUT_DIR: "{{.OUT_DIR}}/{{.LANGUAGE_US}}"
ACTIVE_US: "{{.BINARY_NAME}}.active.en-US.{{.FORMAT}}"
TRANSLATE_US: "{{.BINARY_NAME}}.translate.en-US.{{.FORMAT}}"
TRANSLATE_US_FILE: "{{.US_OUT_DIR}}/{{.TRANSLATE_US}}"

tasks:
# === build =================================================

c:
cmds:
- task: clean

clean:
cmds:
- cmd: rm -rf ./{{.DIST_DIR}}/*

build_generic:
vars:
APPLICATION_SRC: ./src/app/main
APPLICATION_ENTRY: ./src/app/main
SRC_CODE: ./src

cmds:
- echo "cross compiling from {{OS}} to {{.TARGET_OS}}"
- GOOS={{.TARGET_OS}} GOARCH={{.TARGET_ARCH}} go build -o ./dist/{{.TARGET_OS}}/{{.BINARY_NAME}}{{.BINARY_EXT}} -v {{.APPLICATION_SRC}}
- GOOS={{.TARGET_OS}} GOARCH={{.TARGET_ARCH}} go build -o ./{{.DIST_DIR}}/{{.TARGET_OS}}/{{.BINARY_NAME}}{{.BINARY_EXT}} -v {{.APPLICATION_ENTRY}}

sources:
- ./src/**/*.go

generates:
- ./dist/{{.TARGET_OS}}/{{.BINARY_NAME}}{{.BINARY_EXT}}
- ./{{.DIST_DIR}}/{{.TARGET_OS}}/{{.BINARY_NAME}}{{.BINARY_EXT}}

b:
cmds:
Expand All @@ -43,31 +69,48 @@ tasks:
- task: build_generic
vars: { TARGET_OS: darwin, TARGET_ARCH: amd64 }

# === test ==================================================

t:
cmds:
- go test ./...

# === deploy ================================================

d:
cmds:
- task: deploy

dry:
cmds:
- ginkgo -v --dry-run ./...
# currently, this is hardcoded for windows
#
deploy:
vars:
BINARY_EXT: .exe
TARGET_OS: windows
DEPLOY_BINARY: ./{{.DIST_DIR}}/{{.TARGET_OS}}/{{.BINARY_NAME}}{{.BINARY_EXT}}
DEPLOY_US: ./{{.DEPLOY_DIR}}/{{.ACTIVE_US}}

t:
cmds:
- go test ./...
- echo "deploying to location (.env) DEPLOY_TO ==> '$DEPLOY_TO'"
- /bin/cp -f {{.DEPLOY_BINARY}} $DEPLOY_TO
- /bin/cp -f ./{{.DEPLOY_DIR}}/{{.ACTIVE_US}} $DEPLOY_TO

generates:
- $DEPLOY_TO/{{.DEPLOY_BINARY}}
- $DEPLOY_TO/{{.ACTIVE_US}}

preconditions:
- test $DEPLOY_TO
- test -f {{.DEPLOY_BINARY}}
- test -f ./{{.DEPLOY_DIR}}/{{.ACTIVE_US}}

tbd:
cmds:
- task: t
- task: b
- task: d

watchv:
cmds:
- ginkgo watch -v -r -p ./...

watch:
cmds:
- ginkgo watch -r -p ./...
# === ginkgo ================================================

# initialise a test suite for a package. (only 1 per package)
boot:
Expand Down Expand Up @@ -95,40 +138,137 @@ tasks:
cmds:
- ginkgo generate {{.CLI_ARGS}}

dry:
cmds:
- ginkgo -v --dry-run ./...

# === watch ================================================

watchv:
cmds:
- ginkgo watch -v -r -p ./...

watch:
cmds:
- ginkgo watch -r -p ./...

# === lint =================================================

lint:
cmds:
- golangci-lint run

# currently, this is hardcoded for windows
#
deploy:
vars:
BINARY_EXT: .exe
TARGET_OS: windows
DEPLOY_BINARY: ./dist/{{.TARGET_OS}}/{{.BINARY_NAME}}{{.BINARY_EXT}}
DEPLOY_US: ./src/internal/l10n/out/{{.TRANSLATION_US}}
# === coverage =============================================

cover:
cmds:
- echo "deploying to location (.env) DEPLOY_TO ==> '$DEPLOY_TO'"
- /bin/cp -f {{.DEPLOY_BINARY}} $DEPLOY_TO
- /bin/cp -f {{.TRANSLATIONS_DIR}}/{{.TRANSLATION_US}} $DEPLOY_TO
- goveralls -repotoken {{.COVERALLS_TOKEN}}

generates:
- $DEPLOY_TO/{{.DEPLOY_BINARY}}
- $DEPLOY_TO/{{.TRANSLATION_US}}
# === i18n =================================================

preconditions:
- test $DEPLOY_TO
- test -f {{.DEPLOY_BINARY}}
clear:
cmds:
- rm ./{{.OUT_DIR}}/* --recursive

c:
# extract: scans for i18m messages in source code
# - creates empty out/l10n/arcadia.translate.en-US.json
# - extracts messages into out/active.en-GB.json
#
extract:
cmds:
- task: clean
- goi18n extract
-format {{.FORMAT}}
-sourceLanguage {{.SOURCE_LANG}}
-outdir {{.OUT_DIR}}
- echo "✨ Extract from source language {{.SOURCE_LANG}} => Created:"
- echo "---> 📜 {{.OUT_DIR}}/{{.EXTRACT_ACTIVE}}"

clean:
# newt: new translation:
#
newt:
deps: [extract]
cmds:
- cmd: rm -rf dist/*
- test -d {{.US_OUT_DIR}} || mkdir {{.US_OUT_DIR}}
- touch {{.US_OUT_DIR}}/{{.TRANSLATE_US}}
- echo "💦 Generate empty translate file for {{.LANGUAGE_US}} => Created:"
- echo "---> 📜 {{.US_OUT_DIR}}/{{.TRANSLATE_US}}"

cover:
# merge: derive a translation from the default
# we pass the source file (EXTRACT_ACTIVE) as well as the empty
# translation file (TRANSLATE_US) into the merge
# This creates 2 files per language:
#
# xx-yy.active.format
# This file contains messages that should be loaded at runtime.
#
# xx-yy.translate.format
# This file contains messages which should be translated.
#
# When you merge, you can't control the name of the active/translate files, so
# don't rename them, leave as is and do any renaming at the end
#
merge:
cmds:
- goveralls -repotoken {{.COVERALLS_TOKEN}}
- goi18n merge
-format {{.FORMAT}}
-sourceLanguage {{.SOURCE_LANG}}
-outdir ./{{.OUT_DIR}}
"{{.SOURCE_ACTIVE_FILE}}"
"{{.TRANSLATE_US_FILE}}"
- echo "🌐 running merge with files:"
- echo "---> input file📜 {{.SOURCE_ACTIVE}}"
- echo "---> input file📜 {{.TRANSLATE_US_FILE}}"
- echo "🤖 Generate files for {{.LANGUAGE_US}} => Created:"
- echo "---> 📜 active.en-US.{{.FORMAT}} (this contains null doc {})"
- echo "---> 📜 translate.en-US.{{.FORMAT}} (creates the pre-translate doc with hashes)"

# update existing translations
# after running this task, the translation file generated will
# contain only the new translations. Update the active file,
# with the new translations. Also, need to copy the default
# file (active.en-GB.json) back into ./i18n/default
#
# creates ./src/i18n/out/en-US/translate.en-US.json: this is the
# file to be translated. This contains hashes and also contains
# all messages, not just the ones added.
# It is useful to keep all the out file also checked in because, what we
# can do is perform the extract, this generates the out/active/active.en-GB.json
# file, but it contains all the messages not just the new ones. Because we
# have checked it in, we can see the delta. You can just delete the existing
# messages which leaves you with just the new ones. Then we can you this to
# merge in with the previous active file.
#
# copy the source active delta file into out/en-US/translate.en-US.json file,
# then pass this to your translator. This file will contain the new translated
# messages.
#
# The process of updating existing translation still needs some work as it
# is still not understood and the goi18n documentation is severely lacking
# when it comes to the process. I will aim to improve this as my understanding
# improves after experience.
#
# For now, the merge of new translations with existing ones should be done
# manually.
#
update:
deps: [extract]
cmds:
- goi18n merge
-format {{.FORMAT}}
-sourceLanguage {{.SOURCE_LANG}}
-outdir {{.US_OUT_DIR}}
"{{.SOURCE_ACTIVE_FILE}}"
"{{.US_OUT_DIR}}/{{.TRANSLATE_US}}"

# run this after manual translation has occurred to integrate it
# back into the translation file. Unfortunately, this task doesn't
# work properly, because it does not include the hashes. Without
# this task, the new translations must be manually added to the active
# translation file (active.en-US.json).
accept:
cmds:
- goi18n merge
-format {{.FORMAT}}
-sourceLanguage "en-US"
-outdir ./i18n/temp
./{{.OUT_DIR}}/{{.TRANSLATE_US}} ./{{.DEPLOY_DIR}}/{{.ACTIVE_US}}
72 changes: 72 additions & 0 deletions resources/doc/i18n-README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# 🌐 i18n Assistance

This document aims to augment that which appears in the [goi18n project](https://github.com/nicksnyder/go-i18n/) and provide information that can help the client use the i18n functionality defined there and its integration into this template project. The translations process is quite laborious, so this project tries alleviate this process by providing helper tasks which will be documented here also.

## 📁 Directory Structure

The local directory structure is as follows:

- ___default___: contains the translation file created by the __newt__ (new translation task). Actually, this task creates an __active__ file (`active.en-GB.json`) in the `i18n/out` folder, the result of which needs to be manually copied into the __active__ file in the `default` folder.

- ___deploy___: contains all the translations files that are intended to be deployed with the application. There will be one per supported language and by default this template project includes a translation file for __en-US__ (`arcadia.active.en-US.json`)

## ⚙️ Translation Workflow

### ✨ New Translations

__goi18n__ instructs the user to manually create an empty translation message file that they want to add (eg `translate.en-US.json`). This is taken care of by the __newt__ task. Then the requirement is to run the goi18n merge \<active\> command (goi18n merge `arcadia.active.en-US.json` `arcadia.translate.en-US.json`). This has been wrapped up into the __merge__ task and the result is that the translation file `arcadia.translation.en-US.json` is populated with the messages to be translated. So the sequence goes:

- run __newt__ task: (generates default language file `./src/i18n/out/active.en-GB.json` and empty `./src/i18n/out/us-US/arcadia.translation.en-US.json` file). This task can be run from the root folder, __goi18n__ will recursively search the directory tree for files with translate-able content, ie files with template definitions (___i18n.Message___)
- run __merge__ task: derives a translation file for the requested language __en-US__ using 2 files as inputs: source active file (`./src/i18n/out/active.en-GB.json`) and the empty __en-US__ translate file (`./src/i18n/out/us-US/arcadia.translation.en-US.json`), both of which were generated in the previous step.
- hand the translate file to your translator for them to translate
- rename the translate file to the active equivalent (`arcadia.translation.en-US.json`). Save this into the __deploy__ folder. This file will be deployed with the application.

### 🧩 Update Existing Translations (⚠️ not finalised)

__goi18n__ instructs the user to run the following steps:

1. Run `goi18n extract` to update `active.en.toml` with the new messages.
2. Run `goi18n merge active.*.toml` to generate updated `translate.*.toml` files.
3. Translate all the messages in the `translate.*.toml` files.
4. Run `goi18n merge active.*.toml translate.*.toml` to merge the translated messages into the active message files.

___The above description is way too vague and ambiguous. It is for this reason that this process has not been finalised. The intention will be to upgrade the instructions as time goes by and experience is gained.___

However, in this template, the user can execute the following steps:

- run task __update__: this will re-extract messages into `active.en-GB.json` and then runs merge to create an updated translate file.
- hand the translate file to your translator for them to translate
- as before, this translated file should be used to update the active file `arcadia.active.en-US.json` inside the __deploy__ folder.

## 🎓 Task Reference

❗This is a work in progress ...

### 💤 extract

Scans the code base for messages and extracts them into __out/active.en-GB.json__ (The name of the file can't be controlled, it is derived from the language specified). No need to call this task directly.

### 💠 newt

Invokes the `extract` task to extract messages from code. After running this task, the __translate.en-US.json__ file is empty ready to be used as one of the inputs to the merge task (_why do we need an empty input file for the merge? Perhaps the input file instructs the language tag to goi18n_).

Inputs:

- source code

Outputs:

- ./src/i18n/out/active.en-GB.json (messages extracted from code, without hashes)
- ./src/i18n/out/en-US/translate.en-US.json (empty)

### 💠 merge

Inputs:

- ./src/i18n/out/active.en-GB.json
- ./src/i18n/out/en-US/arcadia.translate-en-US.json

Outputs:

- ./src/i18n/out/active.en-US.json
- ./src/i18n/out/translate.en-US.json
26 changes: 26 additions & 0 deletions src/i18n/default/arcadia.active.en-GB.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"foo-bar.arcadia.nav": {
"description": "Foo Bar description",
"other": "foo bar failure '{{.Path}}' (reason: {{.Reason}})"
},
"root-command-config-file-usage": {
"description": "root command config flag usage",
"other": "config file (default is $HOME/{{.ConfigFileName}}.yml)"
},
"root-command-language-usage": {
"description": "root command lang usage",
"other": "'lang' defines the language according to IETF BCP 47"
},
"root-command-long-description": {
"description": "long description for the root command",
"other": "A longer description that spans multiple lines and likely contains\n\t\texamples and usage of using your application. For example:\n\t\t\n\t\tCobra is a CLI library for Go that empowers applications.\n\t\tThis application is a tool to generate the needed files\n\t\tto quickly create a Cobra application."
},
"root-command-short-description": {
"description": "short description for the root command",
"other": "A brief description of your application"
},
"using-config-file": {
"description": "Message to indicate which config is being used",
"other": "Using config file: {{.ConfigFileName}}"
}
}
Loading

0 comments on commit 7e5d425

Please sign in to comment.