1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-12-10 00:31:51 +00:00

Apply formatting to the rest of files

This commit is contained in:
Даниїл Григор'єв 2024-06-20 13:02:02 +03:00
parent 5ff15f3029
commit 2f0a505297
No known key found for this signature in database
GPG Key ID: B890DF16341D8C1D
6 changed files with 423 additions and 429 deletions

View File

@ -1,19 +1,19 @@
{
"name": "electron",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"private": true,
"scripts": {
"startDev": "electron --disable-direct-composition --in-process-gpu . --dev --local",
"startDevGpu": "electron --enable-gpu-rasterization --enable-accelerated-2d-canvas --num-raster-threads=8 --enable-zero-copy . --dev --local",
"start": "electron --disable-direct-composition --in-process-gpu ."
},
"devDependencies": {},
"optionalDependencies": {},
"dependencies": {
"async-lock": "^1.4.1",
"electron": "^30.0.0",
"electron-window-state": "^5.0.3"
}
}
{
"name": "electron",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"private": true,
"scripts": {
"startDev": "electron --disable-direct-composition --in-process-gpu . --dev --local",
"startDevGpu": "electron --enable-gpu-rasterization --enable-accelerated-2d-canvas --num-raster-threads=8 --enable-zero-copy . --dev --local",
"start": "electron --disable-direct-composition --in-process-gpu ."
},
"devDependencies": {},
"optionalDependencies": {},
"dependencies": {
"async-lock": "^1.4.1",
"electron": "^30.0.0",
"electron-window-state": "^5.0.3"
}
}

View File

@ -1,212 +1,212 @@
/**
*
* Run `yarn global add canvas` first
*/
const { createCanvas } = require("canvas");
const fs = require("fs");
const path = require("path");
const outputFolder = path.join(__dirname, "..", "wires", "sets");
const dimensions = 192;
const lineSize = 14;
const lowerLineSize = 32;
const variants = {
first: "#61ef6f",
second: "#5fb2f1",
conflict: "#f74c4c",
};
function hexToRGB(h) {
let r = 0,
g = 0,
b = 0;
// 3 digits
if (h.length == 4) {
r = "0x" + h[1] + h[1];
g = "0x" + h[2] + h[2];
b = "0x" + h[3] + h[3];
// 6 digits
} else if (h.length == 7) {
r = "0x" + h[1] + h[2];
g = "0x" + h[3] + h[4];
b = "0x" + h[5] + h[6];
}
return [+r, +g, +b];
}
function RGBToHSL(r, g, b) {
// Make r, g, and b fractions of 1
r /= 255;
g /= 255;
b /= 255;
// Find greatest and smallest channel values
let cmin = Math.min(r, g, b),
cmax = Math.max(r, g, b),
delta = cmax - cmin,
h = 0,
s = 0,
l = 0;
// Calculate hue
// No difference
if (delta == 0) h = 0;
// Red is max
else if (cmax == r) h = ((g - b) / delta) % 6;
// Green is max
else if (cmax == g) h = (b - r) / delta + 2;
// Blue is max
else h = (r - g) / delta + 4;
h = Math.round(h * 60);
// Make negative hues positive behind 360°
if (h < 0) h += 360;
// Calculate lightness
l = (cmax + cmin) / 2;
// Calculate saturation
s = delta == 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
// Multiply l and s by 100
s = +(s * 100).toFixed(1);
l = +(l * 100).toFixed(1);
return [h, s, l];
}
function HSLToRGB(h, s, l) {
// Must be fractions of 1
s /= 100;
l /= 100;
let c = (1 - Math.abs(2 * l - 1)) * s,
x = c * (1 - Math.abs(((h / 60) % 2) - 1)),
m = l - c / 2,
r = 0,
g = 0,
b = 0;
if (0 <= h && h < 60) {
r = c;
g = x;
b = 0;
} else if (60 <= h && h < 120) {
r = x;
g = c;
b = 0;
} else if (120 <= h && h < 180) {
r = 0;
g = c;
b = x;
} else if (180 <= h && h < 240) {
r = 0;
g = x;
b = c;
} else if (240 <= h && h < 300) {
r = x;
g = 0;
b = c;
} else if (300 <= h && h < 360) {
r = c;
g = 0;
b = x;
}
r = Math.round((r + m) * 255);
g = Math.round((g + m) * 255);
b = Math.round((b + m) * 255);
return [r, g, b];
}
async function run() {
console.log("Running");
const promises = [];
for (const variantId in variants) {
const variantColor = variants[variantId];
const variantHSL = RGBToHSL(...hexToRGB(variantColor));
const darkenedColor = HSLToRGB(variantHSL[0], variantHSL[1] - 15, variantHSL[2] - 20);
const hexDarkenedColor = "rgb(" + darkenedColor.join(",") + ")";
console.log(variantColor, "->", hexToRGB(variantColor), variantHSL, "->", darkenedColor);
const parts = {
forward: [[0.5, 0, 0.5, 1]],
turn: [
[0.5, 0.5, 0.5, 1],
[0.5, 0.5, 1, 0.5],
],
split: [
[0.5, 0.5, 0.5, 1],
[0, 0.5, 1, 0.5],
],
cross: [
[0, 0.5, 1, 0.5],
[0.5, 0, 0.5, 1],
],
};
for (const partId in parts) {
const partLines = parts[partId];
const canvas = createCanvas(dimensions, dimensions);
const context = canvas.getContext("2d");
context.quality = "best";
context.clearRect(0, 0, dimensions, dimensions);
const lineCanvas = createCanvas(dimensions, dimensions);
const lineContext = lineCanvas.getContext("2d");
lineContext.quality = "best";
lineContext.clearRect(0, 0, dimensions, dimensions);
lineContext.strokeStyle = hexDarkenedColor;
lineContext.lineWidth = lowerLineSize;
lineContext.lineCap = "square";
lineContext.imageSmoothingEnabled = false;
// Draw lower lines
partLines.forEach(([x1, y1, x2, y2]) => {
lineContext.beginPath();
lineContext.moveTo(x1 * dimensions, y1 * dimensions);
lineContext.lineTo(x2 * dimensions, y2 * dimensions);
lineContext.stroke();
});
context.globalAlpha = 0.4;
context.drawImage(lineCanvas, 0, 0, dimensions, dimensions);
context.globalAlpha = 1;
context.imageSmoothingEnabled = false;
context.lineCap = "square";
context.strokeStyle = variantColor;
context.lineWidth = lineSize;
// Draw upper lines
partLines.forEach(([x1, y1, x2, y2]) => {
context.beginPath();
context.moveTo(x1 * dimensions, y1 * dimensions);
context.lineTo(x2 * dimensions, y2 * dimensions);
context.stroke();
});
const out = fs.createWriteStream(path.join(outputFolder, variantId + "_" + partId + ".png"));
const stream = canvas.createPNGStream();
stream.pipe(out);
promises.push(new Promise(resolve => stream.on("end", resolve)));
}
}
console.log("Waiting for completion");
await Promise.all(promises);
console.log("Done!");
}
run();
/**
*
* Run `yarn global add canvas` first
*/
const { createCanvas } = require("canvas");
const fs = require("fs");
const path = require("path");
const outputFolder = path.join(__dirname, "..", "wires", "sets");
const dimensions = 192;
const lineSize = 14;
const lowerLineSize = 32;
const variants = {
first: "#61ef6f",
second: "#5fb2f1",
conflict: "#f74c4c",
};
function hexToRGB(h) {
let r = 0,
g = 0,
b = 0;
// 3 digits
if (h.length == 4) {
r = "0x" + h[1] + h[1];
g = "0x" + h[2] + h[2];
b = "0x" + h[3] + h[3];
// 6 digits
} else if (h.length == 7) {
r = "0x" + h[1] + h[2];
g = "0x" + h[3] + h[4];
b = "0x" + h[5] + h[6];
}
return [+r, +g, +b];
}
function RGBToHSL(r, g, b) {
// Make r, g, and b fractions of 1
r /= 255;
g /= 255;
b /= 255;
// Find greatest and smallest channel values
let cmin = Math.min(r, g, b),
cmax = Math.max(r, g, b),
delta = cmax - cmin,
h = 0,
s = 0,
l = 0;
// Calculate hue
// No difference
if (delta == 0) h = 0;
// Red is max
else if (cmax == r) h = ((g - b) / delta) % 6;
// Green is max
else if (cmax == g) h = (b - r) / delta + 2;
// Blue is max
else h = (r - g) / delta + 4;
h = Math.round(h * 60);
// Make negative hues positive behind 360°
if (h < 0) h += 360;
// Calculate lightness
l = (cmax + cmin) / 2;
// Calculate saturation
s = delta == 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
// Multiply l and s by 100
s = +(s * 100).toFixed(1);
l = +(l * 100).toFixed(1);
return [h, s, l];
}
function HSLToRGB(h, s, l) {
// Must be fractions of 1
s /= 100;
l /= 100;
let c = (1 - Math.abs(2 * l - 1)) * s,
x = c * (1 - Math.abs(((h / 60) % 2) - 1)),
m = l - c / 2,
r = 0,
g = 0,
b = 0;
if (0 <= h && h < 60) {
r = c;
g = x;
b = 0;
} else if (60 <= h && h < 120) {
r = x;
g = c;
b = 0;
} else if (120 <= h && h < 180) {
r = 0;
g = c;
b = x;
} else if (180 <= h && h < 240) {
r = 0;
g = x;
b = c;
} else if (240 <= h && h < 300) {
r = x;
g = 0;
b = c;
} else if (300 <= h && h < 360) {
r = c;
g = 0;
b = x;
}
r = Math.round((r + m) * 255);
g = Math.round((g + m) * 255);
b = Math.round((b + m) * 255);
return [r, g, b];
}
async function run() {
console.log("Running");
const promises = [];
for (const variantId in variants) {
const variantColor = variants[variantId];
const variantHSL = RGBToHSL(...hexToRGB(variantColor));
const darkenedColor = HSLToRGB(variantHSL[0], variantHSL[1] - 15, variantHSL[2] - 20);
const hexDarkenedColor = "rgb(" + darkenedColor.join(",") + ")";
console.log(variantColor, "->", hexToRGB(variantColor), variantHSL, "->", darkenedColor);
const parts = {
forward: [[0.5, 0, 0.5, 1]],
turn: [
[0.5, 0.5, 0.5, 1],
[0.5, 0.5, 1, 0.5],
],
split: [
[0.5, 0.5, 0.5, 1],
[0, 0.5, 1, 0.5],
],
cross: [
[0, 0.5, 1, 0.5],
[0.5, 0, 0.5, 1],
],
};
for (const partId in parts) {
const partLines = parts[partId];
const canvas = createCanvas(dimensions, dimensions);
const context = canvas.getContext("2d");
context.quality = "best";
context.clearRect(0, 0, dimensions, dimensions);
const lineCanvas = createCanvas(dimensions, dimensions);
const lineContext = lineCanvas.getContext("2d");
lineContext.quality = "best";
lineContext.clearRect(0, 0, dimensions, dimensions);
lineContext.strokeStyle = hexDarkenedColor;
lineContext.lineWidth = lowerLineSize;
lineContext.lineCap = "square";
lineContext.imageSmoothingEnabled = false;
// Draw lower lines
partLines.forEach(([x1, y1, x2, y2]) => {
lineContext.beginPath();
lineContext.moveTo(x1 * dimensions, y1 * dimensions);
lineContext.lineTo(x2 * dimensions, y2 * dimensions);
lineContext.stroke();
});
context.globalAlpha = 0.4;
context.drawImage(lineCanvas, 0, 0, dimensions, dimensions);
context.globalAlpha = 1;
context.imageSmoothingEnabled = false;
context.lineCap = "square";
context.strokeStyle = variantColor;
context.lineWidth = lineSize;
// Draw upper lines
partLines.forEach(([x1, y1, x2, y2]) => {
context.beginPath();
context.moveTo(x1 * dimensions, y1 * dimensions);
context.lineTo(x2 * dimensions, y2 * dimensions);
context.stroke();
});
const out = fs.createWriteStream(path.join(outputFolder, variantId + "_" + partId + ".png"));
const stream = canvas.createPNGStream();
stream.pipe(out);
promises.push(new Promise(resolve => stream.on("end", resolve)));
}
}
console.log("Waiting for completion");
await Promise.all(promises);
console.log("Done!");
}
run();

View File

@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html>
<head>
<title>shapez</title>
@ -18,5 +18,5 @@
<meta http-equiv="Cache-Control" content="private, max-age=0, no-store, no-cache, must-revalidate" />
<meta http-equiv="Expires" content="0" />
</head>
<body oncontextmenu="return false" style="background: #393747;"></body>
<body oncontextmenu="return false" style="background: #393747"></body>
</html>

View File

@ -1,33 +1,27 @@
{
"extends": [
"@tsconfig/strictest/tsconfig"
],
"include": [
"./js/**/*"
],
"compilerOptions": {
"allowJs": true,
"module": "es2022",
"moduleResolution": "bundler",
"noEmit": true,
"target": "ES2022",
/* JSX Compilation */
"paths": {
"@/*": [
"./js/*"
]
},
"jsx": "react-jsx",
"jsxImportSource": "@",
// remove when comfortable
"exactOptionalPropertyTypes": false,
"noImplicitAny": false,
"noImplicitOverride": false,
"noImplicitReturns": false,
"noPropertyAccessFromIndexSignature": false,
"noUncheckedIndexedAccess": false,
"strictNullChecks": false,
// eslint warns for this
"noUnusedLocals": true,
}
}
{
"extends": ["@tsconfig/strictest/tsconfig"],
"include": ["./js/**/*"],
"compilerOptions": {
"allowJs": true,
"module": "es2022",
"moduleResolution": "bundler",
"noEmit": true,
"target": "ES2022",
/* JSX Compilation */
"paths": {
"@/*": ["./js/*"]
},
"jsx": "react-jsx",
"jsxImportSource": "@",
// remove when comfortable
"exactOptionalPropertyTypes": false,
"noImplicitAny": false,
"noImplicitOverride": false,
"noImplicitReturns": false,
"noPropertyAccessFromIndexSignature": false,
"noUncheckedIndexedAccess": false,
"strictNullChecks": false,
// eslint warns for this
"noUnusedLocals": true
}
}

View File

@ -1,80 +1,80 @@
// Synchronizes all translations
const fs = require("fs");
const path = require("path");
const YAML = require("yaml");
const files = fs
.readdirSync(path.join(__dirname, "translations"))
.filter(x => x.endsWith(".yaml"))
.filter(x => x.indexOf("base-en") < 0);
const originalContents = fs
.readFileSync(path.join(__dirname, "translations", "base-en.yaml"))
.toString("utf-8");
const original = YAML.parse(originalContents);
const placeholderRegexp = /[[<]([a-zA-Z_0-9/-_]+?)[\]>]/gi;
function match(originalObj, translatedObj, path = "/", ignorePlaceholderMismatch = false) {
for (const key in originalObj) {
if (!translatedObj.hasOwnProperty(key)) {
console.warn(" | Missing key", path + key);
translatedObj[key] = originalObj[key];
continue;
}
const valueOriginal = originalObj[key];
const valueMatching = translatedObj[key];
if (typeof valueOriginal !== typeof valueMatching) {
console.warn(" | MISMATCHING type (obj|non-obj) in", path + key);
translatedObj[key] = originalObj[key];
continue;
}
if (typeof valueOriginal === "object") {
match(valueOriginal, valueMatching, path + key + "/", ignorePlaceholderMismatch);
} else if (typeof valueOriginal === "string") {
const originalPlaceholders = [...valueOriginal.matchAll(placeholderRegexp)];
const translatedPlaceholders = [...valueMatching.matchAll(placeholderRegexp)];
if (!ignorePlaceholderMismatch && originalPlaceholders.length !== translatedPlaceholders.length) {
console.warn(
" | Mismatching placeholders in",
path + key,
"->",
originalPlaceholders,
"vs",
translatedPlaceholders
);
translatedObj[key] = originalObj[key];
continue;
}
} else {
console.warn(" | Unknown type: ", typeof valueOriginal);
}
}
for (const key in translatedObj) {
if (!originalObj.hasOwnProperty(key)) {
console.warn(" | Obsolete key", path + key);
delete translatedObj[key];
}
}
}
for (let i = 0; i < files.length; ++i) {
const filename = files[i];
const filePath = path.join(__dirname, "translations", filename);
console.log("Processing", filename);
const translatedContents = fs.readFileSync(filePath).toString("utf-8");
const json = YAML.parse(translatedContents);
match(original, json, "/", filename.toLowerCase().includes("zh-cn"));
const stringified = YAML.stringify(json, {
indent: 4,
simpleKeys: true,
});
fs.writeFileSync(filePath, stringified, "utf-8");
}
// Synchronizes all translations
const fs = require("fs");
const path = require("path");
const YAML = require("yaml");
const files = fs
.readdirSync(path.join(__dirname, "translations"))
.filter(x => x.endsWith(".yaml"))
.filter(x => x.indexOf("base-en") < 0);
const originalContents = fs
.readFileSync(path.join(__dirname, "translations", "base-en.yaml"))
.toString("utf-8");
const original = YAML.parse(originalContents);
const placeholderRegexp = /[[<]([a-zA-Z_0-9/-_]+?)[\]>]/gi;
function match(originalObj, translatedObj, path = "/", ignorePlaceholderMismatch = false) {
for (const key in originalObj) {
if (!translatedObj.hasOwnProperty(key)) {
console.warn(" | Missing key", path + key);
translatedObj[key] = originalObj[key];
continue;
}
const valueOriginal = originalObj[key];
const valueMatching = translatedObj[key];
if (typeof valueOriginal !== typeof valueMatching) {
console.warn(" | MISMATCHING type (obj|non-obj) in", path + key);
translatedObj[key] = originalObj[key];
continue;
}
if (typeof valueOriginal === "object") {
match(valueOriginal, valueMatching, path + key + "/", ignorePlaceholderMismatch);
} else if (typeof valueOriginal === "string") {
const originalPlaceholders = [...valueOriginal.matchAll(placeholderRegexp)];
const translatedPlaceholders = [...valueMatching.matchAll(placeholderRegexp)];
if (!ignorePlaceholderMismatch && originalPlaceholders.length !== translatedPlaceholders.length) {
console.warn(
" | Mismatching placeholders in",
path + key,
"->",
originalPlaceholders,
"vs",
translatedPlaceholders
);
translatedObj[key] = originalObj[key];
continue;
}
} else {
console.warn(" | Unknown type: ", typeof valueOriginal);
}
}
for (const key in translatedObj) {
if (!originalObj.hasOwnProperty(key)) {
console.warn(" | Obsolete key", path + key);
delete translatedObj[key];
}
}
}
for (let i = 0; i < files.length; ++i) {
const filename = files[i];
const filePath = path.join(__dirname, "translations", filename);
console.log("Processing", filename);
const translatedContents = fs.readFileSync(filePath).toString("utf-8");
const json = YAML.parse(translatedContents);
match(original, json, "/", filename.toLowerCase().includes("zh-cn"));
const stringified = YAML.stringify(json, {
indent: 4,
simpleKeys: true,
});
fs.writeFileSync(filePath, stringified, "utf-8");
}

View File

@ -1,83 +1,83 @@
# Translations
The base language is English and can be found [here](base-en.yaml).
## Languages
- [German](base-de.yaml)
- [French](base-fr.yaml)
- [Korean](base-kor.yaml)
- [Dutch](base-nl.yaml)
- [Polish](base-pl.yaml)
- [Portuguese (Brazil)](base-pt-BR.yaml)
- [Portuguese (Portugal)](base-pt-PT.yaml)
- [Russian](base-ru.yaml)
- [Greek](base-el.yaml)
- [Italian](base-it.yaml)
- [Romanian](base-ro.yaml)
- [Swedish](base-sv.yaml)
- [Chinese (Simplified)](base-zh-CN.yaml)
- [Chinese (Traditional)](base-zh-TW.yaml)
- [Spanish](base-es.yaml)
- [Hungarian](base-hu.yaml)
- [Turkish](base-tr.yaml)
- [Japanese](base-ja.yaml)
- [Lithuanian](base-lt.yaml)
- [Arabic](base-ar.yaml)
- [Norwegian](base-no.yaml)
- [Kroatian](base-hr.yaml)
- [Danish](base-da.yaml)
- [Finnish](base-fi.yaml)
- [Catalan](base-cat.yaml)
- [Slovenian](base-sl.yaml)
- [Ukrainian](base-uk.yaml)
- [Indonesian](base-ind.yaml)
- [Serbian](base-sr.yaml)
- [Czech](base-cz.yaml)
(If you want to translate into a new language, see below!)
## Editing existing translations
If you want to edit an existing translation (Fixing typos, updating it to a newer version, etc), you can just use the github file editor to edit the file.
- Click the language you want to edit from the list above
- Click the small "edit" symbol on the top right
<img src="https://i.imgur.com/gZnUQoe.png" alt="edit symbol" width="200">
- Do the changes you wish to do (Be sure **not** to translate placeholders! For example, `<amount> minutes` should get `<amount> Minuten` and **not** `<anzahl> Minuten`!)
- Click "Propose Changes"
<img src="https://i.imgur.com/KT9ZFp6.png" alt="propose changes" width="200">
- Click "Create pull request"
<img src="https://i.imgur.com/oVljvRE.png" alt="create pull request" width="200">
- I will review your changes and make comments, and eventually merge them so they will be in the next release! Be sure to regulary check the created pull request for comments.
## Adding a new language
Please DM me on Discord (tobspr#5407), so I can add the language template for you.
**Important: I am currently not accepting new languages until the wires update is out!**
Please use the following template:
```
Hey, could you add a new translation?
Language: <Language, e.g. 'German'>
Short code: <Short code, e.g. 'de', see below>
Local Name: <Name of your Language, e.g. 'Deutsch'>
```
You can find the short code [here](https://www.science.co.il/language/Codes.php) (In column `Code 2`).
PS: I'm super busy, but I'll give my best to do it quickly!
## Updating a language to the latest version
Run `yarn syncTranslations` in the root directory to synchronize all translations to the latest version! This will remove obsolete keys and add newly added keys. (Run `yarn` before to install packages).
# Translations
The base language is English and can be found [here](base-en.yaml).
## Languages
- [German](base-de.yaml)
- [French](base-fr.yaml)
- [Korean](base-kor.yaml)
- [Dutch](base-nl.yaml)
- [Polish](base-pl.yaml)
- [Portuguese (Brazil)](base-pt-BR.yaml)
- [Portuguese (Portugal)](base-pt-PT.yaml)
- [Russian](base-ru.yaml)
- [Greek](base-el.yaml)
- [Italian](base-it.yaml)
- [Romanian](base-ro.yaml)
- [Swedish](base-sv.yaml)
- [Chinese (Simplified)](base-zh-CN.yaml)
- [Chinese (Traditional)](base-zh-TW.yaml)
- [Spanish](base-es.yaml)
- [Hungarian](base-hu.yaml)
- [Turkish](base-tr.yaml)
- [Japanese](base-ja.yaml)
- [Lithuanian](base-lt.yaml)
- [Arabic](base-ar.yaml)
- [Norwegian](base-no.yaml)
- [Kroatian](base-hr.yaml)
- [Danish](base-da.yaml)
- [Finnish](base-fi.yaml)
- [Catalan](base-cat.yaml)
- [Slovenian](base-sl.yaml)
- [Ukrainian](base-uk.yaml)
- [Indonesian](base-ind.yaml)
- [Serbian](base-sr.yaml)
- [Czech](base-cz.yaml)
(If you want to translate into a new language, see below!)
## Editing existing translations
If you want to edit an existing translation (Fixing typos, updating it to a newer version, etc), you can just use the github file editor to edit the file.
- Click the language you want to edit from the list above
- Click the small "edit" symbol on the top right
<img src="https://i.imgur.com/gZnUQoe.png" alt="edit symbol" width="200">
- Do the changes you wish to do (Be sure **not** to translate placeholders! For example, `<amount> minutes` should get `<amount> Minuten` and **not** `<anzahl> Minuten`!)
- Click "Propose Changes"
<img src="https://i.imgur.com/KT9ZFp6.png" alt="propose changes" width="200">
- Click "Create pull request"
<img src="https://i.imgur.com/oVljvRE.png" alt="create pull request" width="200">
- I will review your changes and make comments, and eventually merge them so they will be in the next release! Be sure to regulary check the created pull request for comments.
## Adding a new language
Please DM me on Discord (tobspr#5407), so I can add the language template for you.
**Important: I am currently not accepting new languages until the wires update is out!**
Please use the following template:
```
Hey, could you add a new translation?
Language: <Language, e.g. 'German'>
Short code: <Short code, e.g. 'de', see below>
Local Name: <Name of your Language, e.g. 'Deutsch'>
```
You can find the short code [here](https://www.science.co.il/language/Codes.php) (In column `Code 2`).
PS: I'm super busy, but I'll give my best to do it quickly!
## Updating a language to the latest version
Run `yarn syncTranslations` in the root directory to synchronize all translations to the latest version! This will remove obsolete keys and add newly added keys. (Run `yarn` before to install packages).