refactored translations to avoid breakage
This commit is contained in:
Executable → Regular
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 1.5 KiB |
+3
-1
@@ -11,7 +11,9 @@
|
|||||||
"build:css": "postcss css/base.css > css/base.min.css",
|
"build:css": "postcss css/base.css > css/base.min.css",
|
||||||
"build:dev": "webpack --mode development",
|
"build:dev": "webpack --mode development",
|
||||||
"build:prod": "webpack --mode production",
|
"build:prod": "webpack --mode production",
|
||||||
"build:i18n": "node scripts/pack-messages.js",
|
"build:i18n": "node scripts/i18n.js",
|
||||||
|
"i18n:missing": "node scripts/i18n.js missing",
|
||||||
|
"i18n:obsolete": "node scripts/i18n.js obsolete",
|
||||||
"vers": "node scripts/gen-version.js",
|
"vers": "node scripts/gen-version.js",
|
||||||
"extract": "formatjs extract src/**/*.jsx --out-file src/i18n/ex/base-en.json --id-interpolation-pattern '[sha512:contenthash:base64:6]'",
|
"extract": "formatjs extract src/**/*.jsx --out-file src/i18n/ex/base-en.json --id-interpolation-pattern '[sha512:contenthash:base64:6]'",
|
||||||
"compile": "formatjs compile"
|
"compile": "formatjs compile"
|
||||||
|
|||||||
+112
@@ -0,0 +1,112 @@
|
|||||||
|
// 1. Takes file with messages extracted via the React Intl Babel plugin and converts it into a file containing
|
||||||
|
// `id: message` pairs in "en" locale.
|
||||||
|
//
|
||||||
|
// 2. Takes all translations and groups them into a single file.
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const globSync = require('glob').sync;
|
||||||
|
const mkdirpSync = require('mkdirp').sync;
|
||||||
|
|
||||||
|
const EXTRACTED_STRINGS = './src/i18n/ex/base-en.json';
|
||||||
|
const LANG_DIR = './src/i18n/';
|
||||||
|
const LANG_PATTERN = './src/i18n/*.json';
|
||||||
|
const FINAL_FILE = './src/messages.json';
|
||||||
|
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
|
||||||
|
function getLocaleFromFileName(filename) {
|
||||||
|
const parts = filename.split('/');
|
||||||
|
return parts[parts.length - 1].split('.json')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called with a parameter?
|
||||||
|
if (args[0] == 'missing' || args[0] == 'obsolete') {
|
||||||
|
// Extract missing or obsolete translations as requested.
|
||||||
|
// Read all translations.
|
||||||
|
const extracted = globSync(LANG_PATTERN)
|
||||||
|
.map((filename) => {
|
||||||
|
const locale = getLocaleFromFileName(filename);
|
||||||
|
const translated = JSON.parse(fs.readFileSync(filename, 'utf8'));
|
||||||
|
|
||||||
|
const dest = {};
|
||||||
|
// Copy messages while skipping missing and obsolete ones.
|
||||||
|
for (let key in translated) {
|
||||||
|
if ((args[0] == 'missing' && translated[key].missing) ||
|
||||||
|
(args[0] == 'obsolete' && translated[key].obsolete)) {
|
||||||
|
dest[key] = translated[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { [locale]: dest };
|
||||||
|
})
|
||||||
|
.reduce((collection, descriptors) => {
|
||||||
|
return { ...collection, ...descriptors };
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
console.log(JSON.stringify(extracted, null, 2)+"\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The formatjs/cli saves extracted messages into a file {'message_id': {defaultMessage: 'default message text', description: '...'}, ...}.
|
||||||
|
// Rewrite them into a single file en.json {'message_id': 'default message text', }.
|
||||||
|
|
||||||
|
// Read master-set of messages in default language.
|
||||||
|
const baseMessages = JSON.parse(fs.readFileSync(EXTRACTED_STRINGS, 'utf8'));
|
||||||
|
|
||||||
|
// Find messages present in baseMessages but missing in translations and vice versa.
|
||||||
|
// Mark missing or obsolete messages as such.
|
||||||
|
globSync(LANG_PATTERN)
|
||||||
|
.map((filename) => {
|
||||||
|
const translated = JSON.parse(fs.readFileSync(filename, 'utf8'));
|
||||||
|
|
||||||
|
// Refresh existing entries with possible new descriptions and default messages, add missing.
|
||||||
|
Object.entries(baseMessages).forEach((ent) => {
|
||||||
|
const [key, value] = ent;
|
||||||
|
translated[key] = {
|
||||||
|
translation: translated[key] ? translated[key].translation : "",
|
||||||
|
defaultMessage: value.defaultMessage,
|
||||||
|
description: value.description,
|
||||||
|
missing: !translated[key],
|
||||||
|
obsolete: false
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Find no longer needed messages.
|
||||||
|
Object.entries(translated).forEach((ent) => {
|
||||||
|
const [key, value] = ent;
|
||||||
|
if (!baseMessages[key] && translated[key]) {
|
||||||
|
// Obsolete, no longer missing.
|
||||||
|
translated[key].missing = false;
|
||||||
|
translated[key].obsolete = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.writeFileSync(filename, JSON.stringify(translated, null, 2)+"\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Combine all translations into a single json {"lang_1": {...}, "lang_2: {...}"}
|
||||||
|
// while removing messages marked as missing or obsolete.
|
||||||
|
|
||||||
|
// Read all translations.
|
||||||
|
const messages = globSync(LANG_PATTERN)
|
||||||
|
.map((filename) => {
|
||||||
|
const locale = getLocaleFromFileName(filename);
|
||||||
|
const translated = JSON.parse(fs.readFileSync(filename, 'utf8'));
|
||||||
|
|
||||||
|
const dest = {};
|
||||||
|
// Copy messages while skipping missing and obsolete ones.
|
||||||
|
for (let key in translated) {
|
||||||
|
if (!translated[key].missing && !translated[key].obsolete) {
|
||||||
|
dest[key] = translated[key].translation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { [locale]: dest };
|
||||||
|
})
|
||||||
|
.reduce((collection, descriptors) => {
|
||||||
|
return { ...collection, ...descriptors };
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
// Write a file with all translations combined.
|
||||||
|
mkdirpSync(path.dirname(FINAL_FILE));
|
||||||
|
fs.writeFileSync(FINAL_FILE, JSON.stringify(messages));
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
// 1. Takes file with messages extracted via the React Intl Babel plugin and converts it into a file containing
|
|
||||||
// `id: message` pairs in "en" locale.
|
|
||||||
//
|
|
||||||
// 2. Takes all translations and groups them into a single file.
|
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
const globSync = require('glob').sync;
|
|
||||||
const mkdirpSync = require('mkdirp').sync;
|
|
||||||
|
|
||||||
const EXTRACTED_STRINGS = './src/i18n/ex/base-en.json';
|
|
||||||
const DEFAULT_TRANSLATION = 'en.json';
|
|
||||||
const LANG_DIR = './src/i18n/';
|
|
||||||
const LANG_PATTERN = './src/i18n/*.json';
|
|
||||||
const FINAL_FILE = './src/messages.json';
|
|
||||||
const TRANSLATIONS = './src/translations.js'
|
|
||||||
|
|
||||||
const MISSING_MARKER = ':!![MISSING]!!:';
|
|
||||||
const OBSOLETE_MARKER = ':!![OBSOLETE]!!:';
|
|
||||||
|
|
||||||
// The formatjs/cli saves extracted messages into a file {'message_id': {defaultMessage: 'default message text', description: '...'}, ...}.
|
|
||||||
// Rewrite them into a single file en.json {'message_id': 'default message text', }.
|
|
||||||
|
|
||||||
// Read master-set of messages in default language.
|
|
||||||
const baseMessages = JSON.parse(fs.readFileSync(EXTRACTED_STRINGS, 'utf8'));
|
|
||||||
// Convert.
|
|
||||||
const en = {};
|
|
||||||
for (const [id, msg] of Object.entries(baseMessages)) {
|
|
||||||
en[id] = msg.defaultMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write extracted strings into default language file.
|
|
||||||
let filename = path.join(LANG_DIR, DEFAULT_TRANSLATION);
|
|
||||||
mkdirpSync(path.dirname(filename));
|
|
||||||
fs.writeFileSync(filename, JSON.stringify(en, null, 2)+"\n");
|
|
||||||
|
|
||||||
// Find messages present in en.json but missing in translations and vice versa.
|
|
||||||
// Mark missing or obsolete messages as such in translation files.
|
|
||||||
globSync(LANG_PATTERN)
|
|
||||||
.map((filename) => {
|
|
||||||
const parts = filename.split('/');
|
|
||||||
if (parts[parts.length-1] != DEFAULT_TRANSLATION) {
|
|
||||||
const translated = JSON.parse(fs.readFileSync(filename, 'utf8'));
|
|
||||||
// Find missing messages.
|
|
||||||
Object.entries(baseMessages).forEach((ent) => {
|
|
||||||
if (!translated.hasOwnProperty(ent[0])) {
|
|
||||||
// Missing translation.
|
|
||||||
translated[ent[0]] = MISSING_MARKER + ent[1];
|
|
||||||
} else if (translated[ent[0]].indexOf(OBSOLETE_MARKER) === 0) {
|
|
||||||
// No longer obsolete. Remove obsolete marker.
|
|
||||||
translated[ent[0]] = translated[ent[0]].substring(0, OBSOLETE_MARKER.length);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Find no longer needed messages.
|
|
||||||
Object.entries(translated).forEach((ent) => {
|
|
||||||
if (!baseMessages.hasOwnProperty(ent[0]) && translated.hasOwnProperty(ent[0])) {
|
|
||||||
let val = translated[ent[0]];
|
|
||||||
if (val.indexOf(MISSING_MARKER) === 0) {
|
|
||||||
// No longer missing.
|
|
||||||
val = val.substring(0, MISSING_MARKER.length);
|
|
||||||
}
|
|
||||||
if (val.indexOf(OBSOLETE_MARKER) !== 0) {
|
|
||||||
val = OBSOLETE_MARKER + val;
|
|
||||||
}
|
|
||||||
translated[ent[0]] = val;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
fs.writeFileSync(filename, JSON.stringify(translated, null, 2)+"\n");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// List of all available translations.
|
|
||||||
const languageList = {};
|
|
||||||
// Combine all translations into a single json {"lang_1": {...}, "lang_2: {...}"}
|
|
||||||
// while removing messages marked as missing or obsolete.
|
|
||||||
|
|
||||||
// Read all translations.
|
|
||||||
const messages = globSync(LANG_PATTERN)
|
|
||||||
.map((filename) => {
|
|
||||||
const parts = filename.split('/');
|
|
||||||
const locale = parts[parts.length - 1].split('.json')[0];
|
|
||||||
const translated = JSON.parse(fs.readFileSync(filename, 'utf8'));
|
|
||||||
languageList[locale] = locale;
|
|
||||||
// Strip messages prefixed with MISSING or OBSOLETE markers.
|
|
||||||
for (let id in translated) {
|
|
||||||
// process.stdout.write("-- handling translation " + id + "; "+ String(translated[id]) + "; in " + String(filename) + "; --\n");
|
|
||||||
if (translated[id].indexOf(OBSOLETE_MARKER) == 0 ||
|
|
||||||
translated[id].indexOf(MISSING_MARKER) == 0) {
|
|
||||||
delete translated[id];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { [locale]: translated };
|
|
||||||
})
|
|
||||||
.reduce((collection, descriptors) => {
|
|
||||||
return { ...collection, ...descriptors };
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
// Write file with all translations combined.
|
|
||||||
mkdirpSync(path.dirname(FINAL_FILE));
|
|
||||||
fs.writeFileSync(FINAL_FILE, JSON.stringify(messages, null, 2)+"\n");
|
|
||||||
@@ -603,7 +603,7 @@
|
|||||||
},
|
},
|
||||||
"sidepanel_title_account_settings": {
|
"sidepanel_title_account_settings": {
|
||||||
"defaultMessage": "Account Settings",
|
"defaultMessage": "Account Settings",
|
||||||
"description": "Sidepanel title for EditAccountView."
|
"description": "Sidepanel title for AccountSettingsView."
|
||||||
},
|
},
|
||||||
"sidepanel_title_archive": {
|
"sidepanel_title_archive": {
|
||||||
"defaultMessage": "Archived Chats",
|
"defaultMessage": "Archived Chats",
|
||||||
|
|||||||
+2
-2
@@ -1272,12 +1272,12 @@
|
|||||||
"obsolete": false
|
"obsolete": false
|
||||||
},
|
},
|
||||||
"grant_permissions": {
|
"grant_permissions": {
|
||||||
"translation": ":!![OBSOLETE]!!:승인",
|
"translation": "승인",
|
||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": true
|
"obsolete": true
|
||||||
},
|
},
|
||||||
"message_not_readable": {
|
"message_not_readable": {
|
||||||
"translation": ":!![OBSOLETE]!!:메시지에접근할수없음",
|
"translation": "메시지에접근할수없음",
|
||||||
"missing": false,
|
"missing": false,
|
||||||
"obsolete": true
|
"obsolete": true
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1290
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user