mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
core: use disposable app.i18n.load
This commit is contained in:
1 parent
756b4e0a40
commit
ce8b77a6f7
3 files changed
+54
-15
No files matched your search
@@ -1,12 +1,13 @@
|
|||||||
/* eslint-disable import/no-dynamic-require */
|
/* eslint-disable import/no-dynamic-require */
|
||||||
/* eslint-disable no-await-in-loop */
|
/* eslint-disable no-await-in-loop */
|
||||||
/* eslint-disable no-eval */
|
/* eslint-disable no-eval */
|
||||||
|
import '../lib/index';
|
||||||
|
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
import { Context } from '../context';
|
import { Context } from '../context';
|
||||||
import i18n from '../lib/i18n';
|
|
||||||
import { Logger } from '../logger';
|
import { Logger } from '../logger';
|
||||||
import { PRIV } from '../model/builtin';
|
import { PRIV } from '../model/builtin';
|
||||||
import * as bus from '../service/bus';
|
import * as bus from '../service/bus';
|
||||||
@@ -79,12 +80,12 @@ export async function locale(pending: string[], fail: string[]) {
|
|||||||
if (p && (await fs.stat(p)).isDirectory() && !fail.includes(i)) {
|
if (p && (await fs.stat(p)).isDirectory() && !fail.includes(i)) {
|
||||||
try {
|
try {
|
||||||
const files = await fs.readdir(p);
|
const files = await fs.readdir(p);
|
||||||
const locales = {};
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const content = await fs.readFile(path.resolve(p, file), 'utf-8');
|
const content = await fs.readFile(path.resolve(p, file), 'utf-8');
|
||||||
locales[file.split('.')[0]] = yaml.load(content);
|
const dict = yaml.load(content);
|
||||||
|
if (typeof dict !== 'object' || !dict) throw new Error('Invalid locale file');
|
||||||
|
app.i18n.load(file.split('.')[0], dict as any);
|
||||||
}
|
}
|
||||||
i18n(locales);
|
|
||||||
logger.info('Locale init: %s', i);
|
logger.info('Locale init: %s', i);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
fail.push(i);
|
fail.push(i);
|
||||||
|
|||||||
@@ -1,33 +1,71 @@
|
|||||||
const locales = {};
|
import { Context, Service } from '../context';
|
||||||
|
|
||||||
|
const translations: Record<string, Record<string, string>[]> = {};
|
||||||
|
|
||||||
|
declare module '../context' {
|
||||||
|
interface Context {
|
||||||
|
i18n: I18nService;
|
||||||
|
}
|
||||||
|
}
|
||||||
declare global {
|
declare global {
|
||||||
interface String {
|
interface String {
|
||||||
translate: (...languages: string[]) => string;
|
translate: (...languages: string[]) => string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class I18nService extends Service {
|
||||||
|
constructor(ctx: Context) {
|
||||||
|
super(ctx, 'i18n', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
load(lang: string, content: Record<string, string>) {
|
||||||
|
if (!translations[lang]) translations[lang] = [];
|
||||||
|
translations[lang].unshift(content);
|
||||||
|
this.caller?.on('dispose', () => {
|
||||||
|
translations[lang] = translations[lang].filter((i) => i !== content);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get(key: string, lang: string) {
|
||||||
|
if (!translations[lang]) return null;
|
||||||
|
for (const t of translations[lang] || []) {
|
||||||
|
if (t[key]) return t[key];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Context.service('i18n');
|
||||||
|
app.i18n = new I18nService(app);
|
||||||
|
|
||||||
String.prototype.translate = function translate(...languages: string[]) {
|
String.prototype.translate = function translate(...languages: string[]) {
|
||||||
if (languages[0]?.startsWith('en')) {
|
if (languages[0]?.startsWith('en')) {
|
||||||
// For most use cases, source text equals to translated text in English.
|
// For most use cases, source text equals to translated text in English.
|
||||||
// So if it doesn't exist, we should use the original text instead of fallback.
|
// So if it doesn't exist, we should use the original text instead of fallback.
|
||||||
return locales[languages[0]]?.[this] || locales['en']?.[this] || this;
|
return app.i18n.get(this, languages[0]) || app.i18n.get(this, 'en') || this;
|
||||||
}
|
}
|
||||||
for (const language of languages) {
|
for (const language of languages.filter(Boolean)) {
|
||||||
if (!language) continue;
|
const curr = app.i18n.get(this, language) || app.i18n.get(this, language.split('_')[0]);
|
||||||
const curr = (locales[language] || {})[this] || (locales[language.split('_')[0]] || {})[this];
|
|
||||||
if (curr) return curr;
|
if (curr) return curr;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @deprecated use ctx.i18n.load instead. */
|
||||||
function load(data: Record<string, Record<string, string>>) {
|
function load(data: Record<string, Record<string, string>>) {
|
||||||
for (const i in data) {
|
for (const i in data) app.i18n.load(i, data[i]);
|
||||||
if (!locales[i]) locales[i] = { __id: i, ...data[i] };
|
|
||||||
else locales[i] = Object.assign(locales[i], data[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export = load;
|
export = load;
|
||||||
|
|
||||||
global.Hydro.locales = locales;
|
global.Hydro.locales = new Proxy(translations, {
|
||||||
|
get(self, lang: string) {
|
||||||
|
if (!self[lang]) return {};
|
||||||
|
return new Proxy(self[lang], {
|
||||||
|
get(s, key: string) {
|
||||||
|
return app.i18n.get(lang, key);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}) as any;
|
||||||
global.Hydro.lib.i18n = load;
|
global.Hydro.lib.i18n = load;
|
||||||
@@ -387,7 +387,7 @@ const homework = buildContestRule({
|
|||||||
},
|
},
|
||||||
showScoreboard: () => true,
|
showScoreboard: () => true,
|
||||||
showSelfRecord: () => true,
|
showSelfRecord: () => true,
|
||||||
showRecord: () => true,
|
showRecord: (tdoc, now) => now > tdoc.endAt,
|
||||||
async scoreboardHeader(isExport, _, tdoc, pdict) {
|
async scoreboardHeader(isExport, _, tdoc, pdict) {
|
||||||
const columns: ScoreboardNode[] = [
|
const columns: ScoreboardNode[] = [
|
||||||
{ type: 'rank', value: _('Rank') },
|
{ type: 'rank', value: _('Rank') },
|
||||||
|
|||||||
Reference in new issue
Block a user