feat: update structure of i18n

This commit is contained in:
obvTiger 2024-12-15 02:15:27 +01:00
parent a48320862c
commit 0f075e9f7f
12 changed files with 139 additions and 28 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
translations.generated.json

View file

@ -1,15 +1,13 @@
### Merged i18n ### Merged i18n
# Centralized Translation Repository # Centralized Translation Repository
This repository manages all multilingual translations for the project in a single JSON file: `languages.json`. The centralized structure ensures consistency and simplifies updates by consolidating all languages in one place. This repository manages all multilingual translations for the project in a single JSON file: `translations.generated.json`. The centralized structure ensures consistency and simplifies updates by consolidating all languages in one place.
### **Translation Format** ### **Translation Format**
The `languages.json` file organizes translations in a nested structure: The `translations.generated.json` file organizes translations in a nested structure:
- **Keys** represent the unique identifiers for each translatable string. - **Keys** represent the unique identifiers for each translatable string, generated automatically from the file structure.
- **Sub-keys** represent the supported language codes (e.g., `en`, `de`, `fr`). - **Sub-keys** represent the supported language codes (e.g., `en`, `de`, `fr`).
- **Values** are the localized translations for each language. - **Values** are the localized translations for each language.
@ -29,8 +27,18 @@ The `languages.json` file organizes translations in a nested structure:
} }
``` ```
### **Using the Project**
All languages are accepted. #### Prerequisites
- Ensure you have [Node.js](https://nodejs.org) installed.
#### Generating the Translations Index
1. **Add or modify translation files**: Place JSON translation files in the appropriate directory structure under the `merged` folder.
2. **Run the generator**:
```bash
node generator.js
```
This will produce the `translations.generated.json` file in the root directory, containing all the translations consolidated into a single JSON object.
### **Contributing** ### **Contributing**
@ -38,19 +46,11 @@ We welcome contributions to improve or expand translations. Please follow these
1. **Fork the repository.** 1. **Fork the repository.**
2. **Create a new branch** for your changes. 2. **Create a new branch** for your changes.
3. **Update the `languages.json` file**: 3. **Update or add translation files**:
- Add new keys or languages where applicable. - Place your JSON files in the appropriate folder structure under `merged`.
- Ensure consistency in the JSON structure. - Run the `generator.js` script to regenerate the `translations.generated.json` file.
4. **Submit a pull request** with a clear description of your changes. 4. **Submit a pull request** with a clear description of your changes.
### **Advantages of a Centralized File**
- **Simplicity**: All translations are stored in one place, making it easy to access and update.
- **Consistency**: Reduces duplication and ensures all keys are synchronized across languages.
- **Scalability**: Adding new keys or languages requires minimal effort.
### **Contact** ### **Contact**
If you have questions or suggestions, feel free to open an issue in the repository. If you have questions or suggestions, feel free to open an issue in the repository.

41
generator.js Normal file
View file

@ -0,0 +1,41 @@
const fs = require('fs');
const path = require('path');
const translationsDir = './merged';
const outputFile = 'translations.generated.json';
function listJsonFiles(dir, prefix = '') {
let files = fs.readdirSync(dir);
let result = {};
files.forEach(file => {
let fullPath = path.join(dir, file);
let stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
let subPrefix = prefix ? `${prefix}.${file}` : file;
Object.assign(result, listJsonFiles(fullPath, subPrefix));
} else if (file.endsWith('.json')) {
let key = `${prefix}.${path.basename(file, '.json')}`;
result[key] = fullPath;
}
});
return result;
}
function generateTranslationsIndex() {
let translations = {};
let files = listJsonFiles(translationsDir);
Object.entries(files).forEach(([key, filePath]) => {
let content = JSON.parse(fs.readFileSync(filePath, 'utf8'));
translations[key] = content;
});
fs.writeFileSync(outputFile, JSON.stringify(translations, null, 4), 'utf8');
console.log(`Translations index generated: ${outputFile}`);
}
generateTranslationsIndex();

View file

@ -0,0 +1,10 @@
{
"de": "Du wurdest auf %s verschoben.",
"en": "You have been moved to %s.",
"fr": "Vous avez éteindre vers %s.",
"it": "Hai essere spostato su %s.",
"pl": "Byłeś przeniesiony do %s.",
"ru": "Ты был перемещен в %s.",
"zh": "你已被移动到 %s.",
"jp": "あなたは %s に移動しました。"
}

View file

@ -0,0 +1,10 @@
{
"de": "Unbekannt",
"en": "Unknown",
"fr": "Inconnu",
"it": "Sconosciuto",
"pl": "Nieznany",
"ru": "Неизвестно",
"zh": "未知",
"jp": "不明"
}

View file

@ -0,0 +1,10 @@
{
"de": "Party erstellen",
"en": "Create party",
"fr": "Créer une partie",
"it": "Crea una partita",
"pl": "Utwórz grupę",
"ru": "Создать группу",
"zh": "创建队伍",
"jp": "グループ作成"
}

View file

@ -0,0 +1,10 @@
{
"de": "Die Party wurde aufgelöst, weil der Party Leiter hat die Party verlassen hat.",
"en": "The party was disbanded because the party leader left the party.",
"fr": "La partie a disparu car le leader de la partie a quitter la partie.",
"it": "La partita è stata disbandata perché il leader della partita ha lasciato la partita.",
"pl": "Grupa została rozłączona, ponieważ lider grupy opuścił grupę.",
"ru": "Группа была расформирована, поскольку лидер группы покинул группу.",
"zh": "队伍因队长离开队伍而解散。",
"jp": "グループは、グループリーダーがグループを離れたため解散しました。"
}

View file

@ -0,0 +1,10 @@
{
"de": "%s hat die Party beigetreten.",
"en": "%s has joined the party.",
"fr": "%s a rejoindre la partie.",
"it": "%s ha partecipato alla partita.",
"pl": "%s dołacono do grupy.",
"ru": "%s присоединился к группе.",
"zh": "%s 加入队伍。",
"jp": "%s はグループに参加しました。"
}

View file

@ -0,0 +1,10 @@
{
"de": "%s hat die Party verlassen.",
"en": "%s has left the party.",
"fr": "%s a quitter la partie.",
"it": "%s ha lasciato la partita.",
"pl": "%s opuścił grupę.",
"ru": "%s покинул группу.",
"zh": "%s 离开队伍。",
"jp": "%s はグループを離れました。"
}

View file

@ -0,0 +1,10 @@
{
"de": "Du hast die Party verlassen.",
"en": "You have left the party.",
"fr": "Vous avez quitter la partie.",
"it": "Hai lasciato la partita.",
"pl": "Opuściłeś grupę.",
"ru": "Ты покинул группу.",
"zh": "你离开队伍。",
"jp": "あなたはグループを離れました。"
}

View file

@ -0,0 +1,10 @@
{
"de": "Du bist nicht in einer Party.",
"en": "You are not in a party.",
"fr": "Vous n'etes pas dans une partie.",
"it": "Non sei in una partita.",
"pl": "Nie jesteś w grupie.",
"ru": "Ты не в группе.",
"zh": "你不在队伍中。",
"jp": "あなたはグループにいません。"
}

View file

@ -1,11 +0,0 @@
{
"party.create": {
"de": "Party erstellen",
"en": "Create party",
"fr": "Créer une partie",
"it": "Crea una partita",
"pl": "Utwórz grupę",
"ru": "Создать группу",
"zh": "创建队伍"
}
}