Added flags to translations
parent
55463a7811
commit
5cb1b8b4da
|
@ -39,21 +39,20 @@ namespace i18n {
|
||||||
email: string;
|
email: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileInfo {
|
|
||||||
name: string;
|
|
||||||
contributors: Contributor[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TranslationFile {
|
export interface TranslationFile {
|
||||||
url: string;
|
path: string;
|
||||||
|
full_url: string;
|
||||||
|
|
||||||
info: FileInfo;
|
|
||||||
translations: Translation[];
|
translations: Translation[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RepositoryTranslation {
|
export interface RepositoryTranslation {
|
||||||
key: string;
|
key: string;
|
||||||
path: string;
|
path: string;
|
||||||
|
|
||||||
|
country_code: string;
|
||||||
|
name: string;
|
||||||
|
contributors: Contributor[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TranslationRepository {
|
export interface TranslationRepository {
|
||||||
|
@ -85,7 +84,7 @@ namespace i18n {
|
||||||
return translated;
|
return translated;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function load_translation_file(url: string) : Promise<TranslationFile> {
|
async function load_translation_file(url: string, path: string) : Promise<TranslationFile> {
|
||||||
return new Promise<TranslationFile>((resolve, reject) => {
|
return new Promise<TranslationFile>((resolve, reject) => {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: url,
|
url: url,
|
||||||
|
@ -98,7 +97,8 @@ namespace i18n {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
file.url = url;
|
file.full_url = url;
|
||||||
|
file.path = path;
|
||||||
//TODO validate file
|
//TODO validate file
|
||||||
resolve(file);
|
resolve(file);
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
|
@ -113,8 +113,8 @@ namespace i18n {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function load_file(url: string) : Promise<void> {
|
export function load_file(url: string, path: string) : Promise<void> {
|
||||||
return load_translation_file(url).then(result => {
|
return load_translation_file(url, path).then(result => {
|
||||||
log.info(LogCategory.I18N, tr("Successfully initialized up translation file from %s"), url);
|
log.info(LogCategory.I18N, tr("Successfully initialized up translation file from %s"), url);
|
||||||
translations = result.translations;
|
translations = result.translations;
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
|
@ -169,6 +169,7 @@ namespace i18n {
|
||||||
current_language?: string;
|
current_language?: string;
|
||||||
|
|
||||||
current_translation_url: string;
|
current_translation_url: string;
|
||||||
|
current_translation_path: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RepositoryConfig {
|
export interface RepositoryConfig {
|
||||||
|
@ -248,65 +249,31 @@ namespace i18n {
|
||||||
config.save_repository_config();
|
config.save_repository_config();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function iterate_translations(callback_entry: (repository: TranslationRepository, entry: TranslationFile) => any, callback_finish: () => any) {
|
export async function iterate_repositories(callback_entry: (repository: TranslationRepository) => any) {
|
||||||
let count = 0;
|
const promises = [];
|
||||||
const update_finish = () => {
|
|
||||||
if(count == 0 && callback_finish)
|
|
||||||
callback_finish();
|
|
||||||
};
|
|
||||||
|
|
||||||
for(const repo of registered_repositories()) {
|
for(const repository of registered_repositories()) {
|
||||||
count++;
|
promises.push(load_repository0(repository, false).then(() => callback_entry(repository)).catch(error => {
|
||||||
load_repository0(repo, false).then(() => {
|
log.warn(LogCategory.I18N, "Failed to fetch repository %s. error: %o", repository.url, error);
|
||||||
for(const translation of repo.translations || []) {
|
}));
|
||||||
const translation_path = repo.url + "/" + translation.path;
|
|
||||||
count++;
|
|
||||||
|
|
||||||
load_translation_file(translation_path).then(file => {
|
|
||||||
if(callback_entry) {
|
|
||||||
try {
|
|
||||||
callback_entry(repo, file);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
//TODO more error handling?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
count--;
|
|
||||||
update_finish();
|
|
||||||
}).catch(error => {
|
|
||||||
log.warn(LogCategory.I18N, tr("Failed to load translation file for repository %s. Translation: %s (%s) Error: %o"), repo.name, translation.key, translation_path, error);
|
|
||||||
|
|
||||||
count--;
|
|
||||||
update_finish();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
count--;
|
|
||||||
update_finish();
|
|
||||||
}).catch(error => {
|
|
||||||
log.warn(LogCategory.I18N, tr("Failed to load repository while iteration: %s (%s). Error: %o"), (repo || {name: "unknown"}).name, (repo || {url: "unknown"}).url, error);
|
|
||||||
|
|
||||||
count--;
|
|
||||||
update_finish();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await Promise.all(promises);
|
||||||
update_finish();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function select_translation(repository: TranslationRepository, entry: TranslationFile) {
|
export function select_translation(repository: TranslationRepository, entry: RepositoryTranslation) {
|
||||||
const cfg = config.translation_config();
|
const cfg = config.translation_config();
|
||||||
|
|
||||||
if(entry && repository) {
|
if(entry && repository) {
|
||||||
cfg.current_language = entry.info.name;
|
cfg.current_language = entry.name;
|
||||||
cfg.current_repository_url = repository.url;
|
cfg.current_repository_url = repository.url;
|
||||||
cfg.current_translation_url = entry.url;
|
cfg.current_translation_url = repository.url + entry.path;
|
||||||
|
cfg.current_translation_path = entry.path;
|
||||||
} else {
|
} else {
|
||||||
cfg.current_language = undefined;
|
cfg.current_language = undefined;
|
||||||
cfg.current_repository_url = undefined;
|
cfg.current_repository_url = undefined;
|
||||||
cfg.current_translation_url = undefined;
|
cfg.current_translation_url = undefined;
|
||||||
|
cfg.current_translation_path = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
config.save_translation_config();
|
config.save_translation_config();
|
||||||
|
@ -318,7 +285,7 @@ namespace i18n {
|
||||||
|
|
||||||
if(cfg.current_translation_url) {
|
if(cfg.current_translation_url) {
|
||||||
try {
|
try {
|
||||||
await load_file(cfg.current_translation_url);
|
await load_file(cfg.current_translation_url, cfg.current_translation_path);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
createErrorModal(tr("Translation System"), tr("Failed to load current selected translation file.") + "<br>File: " + cfg.current_translation_url + "<br>Error: " + error + "<br>" + tr("Using default fallback translations.")).open();
|
createErrorModal(tr("Translation System"), tr("Failed to load current selected translation file.") + "<br>File: " + cfg.current_translation_url + "<br>Error: " + error + "<br>" + tr("Using default fallback translations.")).open();
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,7 +157,7 @@ namespace Modals {
|
||||||
|
|
||||||
let Regex = {
|
let Regex = {
|
||||||
//DOMAIN<:port>
|
//DOMAIN<:port>
|
||||||
DOMAIN: /^(localhost|((([a-zA-Z0-9_-]{0,63}\.){0,253})?[a-zA-Z0-9_-]{0,63}\.[a-zA-Z]{2,5}))(|:(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[0-5]?[0-9]{1,4}))$/,
|
DOMAIN: /^(localhost|((([a-zA-Z0-9_-]{0,63}\.){0,253})?[a-zA-Z0-9_-]{0,63}\.[a-zA-Z]{2,64}))(|:(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[0-5]?[0-9]{1,46}))$/,
|
||||||
//IP<:port>
|
//IP<:port>
|
||||||
IP_V4: /(^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(|:(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[0-5]?[0-9]{1,4}))$/,
|
IP_V4: /(^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(|:(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[0-5]?[0-9]{1,4}))$/,
|
||||||
IP_V6: /(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/,
|
IP_V6: /(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/,
|
||||||
|
|
|
@ -611,7 +611,7 @@ namespace Modals {
|
||||||
};
|
};
|
||||||
|
|
||||||
tag_loading.show();
|
tag_loading.show();
|
||||||
i18n.iterate_translations((repo, entry) => {
|
i18n.iterate_repositories(repo => {
|
||||||
let repo_tag = tag_list.find("[repository=\"" + repo.unique_id + "\"]");
|
let repo_tag = tag_list.find("[repository=\"" + repo.unique_id + "\"]");
|
||||||
if (repo_tag.length == 0) {
|
if (repo_tag.length == 0) {
|
||||||
repo_tag = template.renderTag({
|
repo_tag = template.renderTag({
|
||||||
|
@ -639,59 +639,63 @@ namespace Modals {
|
||||||
tag_list.append(repo_tag);
|
tag_list.append(repo_tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tag = template.renderTag({
|
for(const translation of repo.translations) {
|
||||||
type: "translation",
|
const tag = template.renderTag({
|
||||||
name: entry.info.name || entry.url,
|
type: "translation",
|
||||||
id: repo.unique_id,
|
name: translation.name || translation.path,
|
||||||
selected: i18n.config.translation_config().current_translation_url == entry.url
|
id: repo.unique_id,
|
||||||
});
|
country_code: translation.country_code,
|
||||||
tag.find(".button-info").on('click', e => {
|
selected: i18n.config.translation_config().current_translation_path == translation.path
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
const info_modal = createModal({
|
|
||||||
header: tr("Translation info"),
|
|
||||||
body: () => {
|
|
||||||
const tag = $("#settings-translations-list-entry-info").renderTag({
|
|
||||||
type: "translation",
|
|
||||||
name: entry.info.name,
|
|
||||||
url: entry.url,
|
|
||||||
repository_name: repo.name,
|
|
||||||
contributors: entry.info.contributors || []
|
|
||||||
});
|
|
||||||
|
|
||||||
tag.find(".button-info").on('click', () => display_repository_info(repo));
|
|
||||||
|
|
||||||
return tag;
|
|
||||||
},
|
|
||||||
footer: () => {
|
|
||||||
let footer = $.spawn("div");
|
|
||||||
footer.addClass("modal-button-group");
|
|
||||||
footer.css("margin-top", "5px");
|
|
||||||
footer.css("margin-bottom", "5px");
|
|
||||||
footer.css("text-align", "right");
|
|
||||||
|
|
||||||
let buttonOk = $.spawn("button");
|
|
||||||
buttonOk.text(tr("Close"));
|
|
||||||
buttonOk.click(() => info_modal.close());
|
|
||||||
footer.append(buttonOk);
|
|
||||||
|
|
||||||
return footer;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
info_modal.open()
|
tag.find(".button-info").on('click', e => {
|
||||||
});
|
e.preventDefault();
|
||||||
tag.on('click', e => {
|
|
||||||
if (e.isDefaultPrevented()) return;
|
|
||||||
i18n.select_translation(repo, entry);
|
|
||||||
tag_list.find(".selected").removeClass("selected");
|
|
||||||
tag.addClass("selected");
|
|
||||||
|
|
||||||
restart_hint.show();
|
const info_modal = createModal({
|
||||||
});
|
header: tr("Translation info"),
|
||||||
tag.insertAfter(repo_tag)
|
body: () => {
|
||||||
}, () => {
|
const tag = $("#settings-translations-list-entry-info").renderTag({
|
||||||
tag_loading.hide();
|
type: "translation",
|
||||||
});
|
name: translation.name,
|
||||||
|
url: translation.path,
|
||||||
|
repository_name: repo.name,
|
||||||
|
contributors: translation.contributors || []
|
||||||
|
});
|
||||||
|
|
||||||
|
tag.find(".button-info").on('click', () => display_repository_info(repo));
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
},
|
||||||
|
footer: () => {
|
||||||
|
let footer = $.spawn("div");
|
||||||
|
footer.addClass("modal-button-group");
|
||||||
|
footer.css("margin-top", "5px");
|
||||||
|
footer.css("margin-bottom", "5px");
|
||||||
|
footer.css("text-align", "right");
|
||||||
|
|
||||||
|
let buttonOk = $.spawn("button");
|
||||||
|
buttonOk.text(tr("Close"));
|
||||||
|
buttonOk.click(() => info_modal.close());
|
||||||
|
footer.append(buttonOk);
|
||||||
|
|
||||||
|
return footer;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
info_modal.open()
|
||||||
|
});
|
||||||
|
tag.on('click', e => {
|
||||||
|
if (e.isDefaultPrevented()) return;
|
||||||
|
i18n.select_translation(repo, translation);
|
||||||
|
tag_list.find(".selected").removeClass("selected");
|
||||||
|
tag.addClass("selected");
|
||||||
|
|
||||||
|
restart_hint.show();
|
||||||
|
});
|
||||||
|
tag.insertAfter(repo_tag);
|
||||||
|
}
|
||||||
|
}).then(() => tag_loading.hide()).catch(error => {
|
||||||
|
console.error(error);
|
||||||
|
/* this should NEVER happen */
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue