Skip to content

Commit

Permalink
i18n + FR (UnchartedBull#1610)
Browse files Browse the repository at this point in the history
* add localization tags and 3 translation examples

* build all locales, warn on missing translation

* Version française V1.0 de la traduction

* delete yarn.lock

* update package.json with upstream

* re-add @angular/localize

* fix merge

* re-add extract command

* add ids

* replace added spans by ng-containers

* fix duplicate id

* replace spans by ng-containers

* basic docs

* Prise en compte des review pour la traduction française V1.00

* remove irrelevant change

* cleanup angular.json

* fix FR translations and merge ids

* revert to fr instead of fr-FR

* revert fr-FR to fr

* fix targets that were sources

* revert out-file

* revert package-lock

* install angular i18n

* fix build issues

* enable serving custom locales, build detects host lang

* update command name

* correct source language

* update locales

* add target language

* add missing semicolons

* fix duplicate url setting

* fix sourcelocale basehref

* fix typo

* Nettoyage de coquilles de traduction fance V1.00

* remove irrelevant files

* Nettoyage de doublons de traduction France V1.00

* fix adjust screen

* fix spacing

* comment fixes

* translation adjustments

* please linter

* please linter

* trailing whitespace

* lint autofix

* use lodash and update package-lock.json

* revert lodash

Co-authored-by: EtherIoo <[email protected]>
Co-authored-by: UnchartedBull <[email protected]>
  • Loading branch information
3 people committed May 12, 2021
1 parent de8250c commit a3d4c64
Show file tree
Hide file tree
Showing 23 changed files with 7,733 additions and 10,982 deletions.
30 changes: 24 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
If you can think of something nice to add or want to change / extend some of the functionality, feel free to create a Pull Request or an Issue. Please make sure to follow the code style (.prettierrc is included in the GitHub) and not break any of the existing functionality. Any help is greatly appreciated!
## Setting up the repository and build the package

## Setting up the repository and build the package

## Prerequisites

- NodeJS v14
Expand All @@ -19,44 +21,60 @@ To setup a local environment you need to do the following steps:
- Start the Live Server: `npm run start` or `npm run start:big`
- If you want to package OctoDash, so you can install it on your Raspberry Pi: `npm run pack`

# Languages
## Languages

To launch the app in development mode in a specific locale instead of the source english locale, use

To launch the app in development mode in a specific locale instead of the source english locale, use
```
npm run start --serve="--configuration=<lang>"
```

## Add a new language
For a list of available locales have a look at the `angular.json` (`projects.OctoDash.i18n.locales`) file.

### Add a new language

To add a language to the list of supported languages, follow these steps:

- find your language code in [this list](https://github.com/angular/angular/tree/master/packages/common/locales) (angular country codes are not all standard)
- in src/locale, duplicate an existing locale (or run `npm run locale:extract` to generate a new locale file)
- rename the file to include your language code in the format `messages.<languageCode>.xlf`
- in the `<file>` tag (second line of the xlf file) adapt `source-language="<languageCode>"` to your language code
- add the translations for your language between `target` tags
- add your language reference in `angular.json`
- add your language reference in `angular.json`

- `Projects.OctoDash.i18n.locales`

- add:

```
"<lang>": {
"translation": "src/locale/messages.<lang>.xlf",
"baseHref": ""
}
}
```

- `Projects.OctoDash.architect.build.configurations.production.localize`.

- add:

```
"<lang>"
```

- `Projects.OctoDash.architect.build.configurations`.

- add:

```
"<lang>": {
"localize": ["<lang>"]
},
```

- `Projects.OctoDash.architect.serve.configurations`.

- add:

```
"<lang>": {
"browserTarget": "OctoDash:build:<lang>"
Expand All @@ -65,4 +83,4 @@ To add a language to the list of supported languages, follow these steps:

## Update translations IDs and sources

To update translations with the latest codebase and IDs, run `npm run update:locales`. Only commit the files that do not have a date, these are only backups of the locale versions before the update.
To update translations with the latest codebase and IDs, run `npm run locale:update`. Only commit the files that do not have a date, these are only backups of the locale versions before the update.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ For more info have a look at the [wiki](https://github.com/UnchartedBull/OctoDas
- You can press multiple arrows directly after another in the control view. All actions will be executed in series, even if the prior didn't finish
- The six actions on the right in the control view can be customized. They can either send GCode commands to your printer, restart OctoPrint or your Pi and even open iFrames so you can view your camera
- You can adjust the temperatures and fan speed in the home screen by pressing on their icons, if you want to set them to zero, just tap the value once (v1.4.1 and up)
- OctoDash will start in your host's language if it is supported. You can start OctoDash in a different supported language by starting it with `LANG=fr_FR.UTF-8 octodash`.
- OctoDash will start in your host's language if it is supported. You can start OctoDash in a different supported language by starting it with `LANG=fr_FR.UTF-8 octodash`. Currently supported languages are: `fr_FR.UTF-8`, english will be used if your requested language isn't available

## Demo

If you want to see OctoDash in action, here is an awesome video from Nick on [YouTube](https://youtu.be/YI_c-DY6zU4)
If you want to see OctoDash in action, here is an awesome video from Nick on [YouTube](https://youtu.be/YI_c-DY6zU4) there is also a video available from Chris Riley, which also shows the installation process on [YouTube](https://youtu.be/kwo3HMBnqC4)

## Screenshots

Expand Down Expand Up @@ -97,7 +97,7 @@ If you encounter an issue, while using OctoDash please have a look at the [wiki]

## Bugs and more

If you find a bug, please open an issue, so I can have a look at it. Please also add the steps to reproduce and the .gcode file. Thank you!
If you find a bug, please open an issue, so I can have a look at it. Please also add the steps to reproduce and the .gcode file (if applicable). Thank you!

## Contributing

Expand Down
15 changes: 5 additions & 10 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,16 @@
},
"locales": {
"fr": {
"translation": "src/locale/messages.fr.xlf",
"baseHref": ""
}
"translation": "src/locale/messages.fr.xlf",
"baseHref": ""
}
}
},
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"allowedCommonJsDependencies": [
"lottie-web"
],
"allowedCommonJsDependencies": ["lottie-web"],
"aot": true,
"outputPath": "dist",
"index": "src/index.html",
Expand Down Expand Up @@ -65,10 +63,7 @@
"localize": ["fr"]
},
"production": {
"localize": [
"en",
"fr"
],
"localize": ["en", "fr"],
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
Expand Down
162 changes: 77 additions & 85 deletions helper/locale.js
Original file line number Diff line number Diff line change
@@ -1,94 +1,86 @@
module.exports = {
/* eslint-disable @typescript-eslint/no-var-requires */

// returns the correct supported locale given the LANG variable
getLocale() {
const angularConf = require('../angular.json');
const i18n = angularConf.projects.OctoDash.i18n;
let lang;
try {
// Detect if environment LANG is set
// if it is defined, convert LANG from ie 'en_US.UTF-8' to 'en-US'
// if not defined, set it to the source locale
lang = process.env['LANG']
? process.env['LANG'].split('.')[0].replace('_', '-')
: i18n.sourceLocale.code;
} catch(e) {
// LANG was populated with something else than a standard locale code
lang = i18n.sourceLocale.code;
}
// Check if exact LANG exists in our locales
const exactLocale = Object.keys(i18n.locales).includes(lang) && lang;
// Make the short version, convert ie 'en-US' to 'en'
const shortLang = lang.split('-')[0];
// Check if short LANG exists in our locales
// This matches 'fr-CA' to 'fr' if 'fr-CA' is not defined but 'fr' is
const approximateLocale = Object.keys(i18n.locales).includes(shortLang) && shortLang;
// Define locale by either the exact, approximate, or source locale in this order
const locale = exactLocale || approximateLocale || i18n.sourceLocale.code;
console.info('selected language: ' + locale);
return locale;
},
function getLocale() {
const i18n = require('../angular.json').projects.OctoDash.i18n;
let lang;
try {
// Detect if environment LANG is set
// if it is defined, convert LANG from ie 'en_US.UTF-8' to 'en-US'
// if not defined, set it to the source locale
lang = process.env['LANG'] ? process.env['LANG'].split('.')[0].replace('_', '-') : i18n.sourceLocale.code;
} catch (e) {
// LANG was populated with something else than a standard locale code
lang = i18n.sourceLocale.code;
}
// Check if exact LANG exists in our locales
const exactLocale = Object.keys(i18n.locales).includes(lang) && lang;
// Make the short version, convert ie 'en-US' to 'en'
const shortLang = lang.split('-')[0];
// This matches 'fr-CA' to 'fr' if 'fr-CA' is not defined but 'fr' is
const approximateLocale = Object.keys(i18n.locales).includes(shortLang) && shortLang;
// Define locale by either the exact, approximate, or source locale in this order
const locale = exactLocale || approximateLocale || i18n.sourceLocale.code;
console.info('selected language: ' + locale);
return locale;
}

// updates all supported locales consuming an updated messages.xlf
updateLocales() {
const fs = require('fs');
const xliff = require('xliff');
// updates all supported locales consuming an updated messages.xlf
function updateLocales() {
const fs = require('fs');
const xliff = require('xliff');

// list all existing locales
// transtaledXLFs = [{
// filename: 'messages.fr.xlf',
// lang: 'fr',
// }]
let translatedXLFs = [];
const filenames = fs.readdirSync('./src/locale');
for (filename of filenames) {
const match = filename.match(/messages.(..|..-..).xlf/);
if (match) {
const lang = match[1];
translatedXLFs.push({ filename, lang });
}
// list all existing locales
let translatedXLFs = [];
const filenames = fs.readdirSync('./src/locale');
for (let filename of filenames) {
const match = filename.match(/messages.(..|..-..).xlf/);
if (match) {
const lang = match[1];
translatedXLFs.push({ filename, lang });
}
}

// get extracted messages
const extractedXLF = fs.readFileSync('./src/locale/messages.xlf').toString();
xliff.xliff12ToJs(extractedXLF, (err, extracted) => {
if (err) throw new Error(err.message);
// get extracted messages
const extractedXLF = fs.readFileSync('./src/locale/messages.xlf').toString();
xliff.xliff12ToJs(extractedXLF, (err, extracted) => {
if (err) throw new Error(err.message);

// for each supported locale
for (translatedXLFRef of translatedXLFs) {
const translatedXLF = fs.readFileSync(`./src/locale/${translatedXLFRef.filename}`).toString();
// for each supported locale
for (let translatedXLFRef of translatedXLFs) {
const translatedXLF = fs.readFileSync(`./src/locale/${translatedXLFRef.filename}`).toString();

// load this locale
xliff.xliff12ToJs(translatedXLF, (err, translated) => {
if (err) throw new Error(err.message);
// load this locale
xliff.xliff12ToJs(translatedXLF, (err, translated) => {
if (err) throw new Error(err.message);

// hard copy of messages.xlf
const newTranslation = JSON.parse(JSON.stringify(extracted));
newTranslation.targetLanguage = translated.targetLanguage;
// transfer the locale's translations to the copy of the extracted locale
for (id in newTranslation.resources['ng2.template']) {
const source = translated.resources['ng2.template'];
const target = newTranslation.resources['ng2.template'];
// only copy if the translation has a target
if (source[id]) {
target[id].target = source[id].target;
}
// hard copy of messages.xlf
const newTranslation = JSON.parse(JSON.stringify(extracted));
newTranslation.targetLanguage = translated.targetLanguage;
// transfer the locale's translations to the copy of the extracted locale
for (let id in newTranslation.resources['ng2.template']) {
const source = translated.resources['ng2.template'];
const target = newTranslation.resources['ng2.template'];
// only copy if the translation has a target
if (source[id]) {
target[id].target = source[id]?.target || '';
}
// backup the previous version of the locale and write the new locale
xliff.jsToXliff12(newTranslation, (err, result) => {
if (err) throw new Error(err.message);
const now = new Date();
fs.renameSync(
`./src/locale/${translatedXLFRef.filename}`,
`./src/locale/messages.${translatedXLFRef.lang}-${now.toISOString()}.xlf`
);
console.info(`updating ${translatedXLFRef.filename}...`);
fs.writeFileSync(`./src/locale/${translatedXLFRef.filename}`, result);
})
})
}
// remove extracted messages
fs.unlinkSync('./src/locale/messages.xlf');
})
}
};
}
// backup the previous version of the locale and write the new locale
xliff.jsToXliff12(newTranslation, (err, result) => {
if (err) throw new Error(err.message);
const now = new Date();
fs.renameSync(
`./src/locale/${translatedXLFRef.filename}`,
`./src/locale/messages.${translatedXLFRef.lang}-${now.toISOString()}.xlf`,
);
console.info(`updating ${translatedXLFRef.filename}...`);
fs.writeFileSync(`./src/locale/${translatedXLFRef.filename}`, result);
});
});
}
// remove extracted messages
fs.unlinkSync('./src/locale/messages.xlf');
});
}

module.exports = { getLocale, updateLocales };
2 changes: 0 additions & 2 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ const Store = require('electron-store');
const activateListeners = require('./helper/listener');
const electron = require('./helper/electron.js');

let window;

function createWindow() {
const _store = new Store();
const properties = electron.configure(process.argv.slice(1))
Expand Down
Loading

0 comments on commit a3d4c64

Please sign in to comment.