This commit is contained in:
syuilo 2018-07-06 12:17:38 +09:00
parent 8e3d56fdb9
commit e956dd62b5
10 changed files with 49 additions and 312 deletions

View file

@ -20,7 +20,7 @@ import * as replace from 'gulp-replace';
import * as htmlmin from 'gulp-htmlmin'; import * as htmlmin from 'gulp-htmlmin';
const uglifyes = require('uglify-es'); const uglifyes = require('uglify-es');
import locales from './locales'; const locales = require('./locales');
import { fa } from './src/build/fa'; import { fa } from './src/build/fa';
const client = require('./built/client/meta.json'); const client = require('./built/client/meta.json');
import config from './src/config'; import config from './src/config';

27
locales/index.js Normal file
View file

@ -0,0 +1,27 @@
/**
* Languages Loader
*/
const fs = require('fs');
const yaml = require('js-yaml');
const loadLang = lang => yaml.safeLoad(
fs.readFileSync(`./locales/${lang}.yml`, 'utf-8'));
const native = loadLang('ja');
const langs = {
'de': loadLang('de'),
'en': loadLang('en'),
'fr': loadLang('fr'),
'ja': native,
'pl': loadLang('pl'),
'es': loadLang('es')
};
Object.entries(langs).map(([, locale]) => {
// Extend native language (Japanese)
locale = Object.assign({}, native, locale);
});
module.exports = langs;

View file

@ -1,34 +0,0 @@
/**
* Languages Loader
*/
import * as fs from 'fs';
import * as yaml from 'js-yaml';
export type LangKey = 'de' | 'en' | 'fr' | 'ja' | 'pl' | 'es';
export type LocaleObject = { [key: string]: any };
const loadLang = (lang: LangKey) => yaml.safeLoad(
fs.readFileSync(`./locales/${lang}.yml`, 'utf-8')) as LocaleObject;
const native = loadLang('ja');
const langs: { [key: string]: LocaleObject } = {
'de': loadLang('de'),
'en': loadLang('en'),
'fr': loadLang('fr'),
'ja': native,
'pl': loadLang('pl'),
'es': loadLang('es')
};
Object.entries(langs).map(([, locale]) => {
// Extend native language (Japanese)
locale = Object.assign({}, native, locale);
});
export function isAvailableLanguage(lang: string): lang is LangKey {
return lang in langs;
}
export default langs;

View file

@ -2,7 +2,7 @@
* Replace i18n texts * Replace i18n texts
*/ */
import locale, { isAvailableLanguage, LocaleObject } from '../../locales'; const locale = require('../../locales');
export default class Replacer { export default class Replacer {
private lang: string; private lang: string;
@ -16,8 +16,8 @@ export default class Replacer {
this.replacement = this.replacement.bind(this); this.replacement = this.replacement.bind(this);
} }
private get(path: string, key: string): string { public get(path: string, key: string): string {
if (!isAvailableLanguage(this.lang)) { if (!(this.lang in locale)) {
console.warn(`lang '${this.lang}' is not supported`); console.warn(`lang '${this.lang}' is not supported`);
return key; // Fallback return key; // Fallback
} }
@ -28,7 +28,7 @@ export default class Replacer {
if (path) { if (path) {
if (text.hasOwnProperty(path)) { if (text.hasOwnProperty(path)) {
text = text[path] as LocaleObject; text = text[path];
} else { } else {
console.warn(`path '${path}' not found in '${this.lang}'`); console.warn(`path '${path}' not found in '${this.lang}'`);
return key; // Fallback return key; // Fallback
@ -38,7 +38,7 @@ export default class Replacer {
// Check the key existance // Check the key existance
const error = key.split('.').some(k => { const error = key.split('.').some(k => {
if (text.hasOwnProperty(k)) { if (text.hasOwnProperty(k)) {
text = (text as LocaleObject)[k]; text = text[k];
return false; return false;
} else { } else {
return true; return true;

View file

@ -17,7 +17,7 @@ block main
p#desc= desc[lang] || desc['ja'] p#desc= desc[lang] || desc['ja']
section section
h2 %i18n:docs.api.endpoints.params% h2= i18n('docs.api.endpoints.params')
+propTable(params) +propTable(params)
if paramDefs if paramDefs
@ -28,5 +28,5 @@ block main
if res if res
section section
h2 %i18n:docs.api.endpoints.res% h2= i18n('docs.api.endpoints.res')
+propTable(res) +propTable(res)

View file

@ -1,201 +0,0 @@
/**
* Gulp tasks
*/
import * as fs from 'fs';
import * as path from 'path';
import * as glob from 'glob';
import * as gulp from 'gulp';
import * as pug from 'pug';
import * as yaml from 'js-yaml';
import * as mkdirp from 'mkdirp';
import locales from '../../../../locales';
import I18nReplacer from '../../../build/i18n';
import fa from '../../../build/fa';
import config from './../../../config';
import generateVars from '../vars';
import { Context } from 'cafy';
import ObjectContext from 'cafy/built/types/object';
const langs = Object.keys(locales);
const kebab = (string: string) => string.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/\s+/g, '-').toLowerCase();
const parseParam = (param: any) => {
const id = param.type.match(/^id\((.+?)\)|^id/);
const entity = param.type.match(/^entity\((.+?)\)/);
const isObject = /^object/.test(param.type);
const isDate = /^date/.test(param.type);
const isArray = /\[\]$/.test(param.type);
if (id) {
param.kind = 'id';
param.type = 'string';
param.entity = id[1];
if (isArray) {
param.type += '[]';
}
}
if (entity) {
param.kind = 'entity';
param.type = 'object';
param.entity = entity[1];
if (isArray) {
param.type += '[]';
}
}
if (isObject) {
param.kind = 'object';
}
if (isDate) {
param.kind = 'date';
param.type = 'string';
if (isArray) {
param.type += '[]';
}
}
return param;
};
// WIP type
const parseEPDefParam = (key: string, param: Context) => {
return Object.assign({
name: key,
type: param.getType()
}, param.data);
};
const sortParams = (params: Array<{name: string}>) => {
params.sort((a, b) => {
if (a.name < b.name)
return -1;
if (a.name > b.name)
return 1;
return 0;
});
return params;
};
// WIP type
const extractDefs = (params: Context[]) => {
let defs: any[] = [];
params.forEach(param => {
if (param.data && param.data.ref) {
const props = (param as ObjectContext<any>).props;
defs.push({
name: param.data.ref,
params: sortParams(Object.keys(props).map(k => parseEPDefParam(k, props[k])))
});
const childDefs = extractDefs(Object.keys(props).map(k => props[k]));
defs = defs.concat(childDefs);
}
});
return sortParams(defs);
};
gulp.task('doc:api', [
'doc:api:endpoints',
'doc:api:entities'
]);
gulp.task('doc:api:endpoints', ['build:ts'], async () => {
const commonVars = await generateVars();
glob('./built/server/api/endpoints/**/*.js', (globErr, files) => {
if (globErr) {
console.error(globErr);
return;
}
console.log(files.map(file => require('../../../../' + file)));
files.map(file => require('../../../../' + file)).filter(x => x.meta).map(x => x.meta).forEach(ep => {
console.log(ep);
const vars = {
endpoint: ep.name,
url: {
host: config.api_url,
path: ep.name
},
desc: ep.desc,
// @ts-ignore
params: sortParams(ep.params.map(p => parseEPDefParam(p))),
paramDefs: extractDefs(ep.params),
};
langs.forEach(lang => {
pug.renderFile('./src/client/docs/api/endpoints/view.pug', Object.assign({}, vars, {
lang,
title: ep.name,
src: `https://github.com/syuilo/misskey/tree/master/src/client/docs/api/endpoints/${ep.name}.yaml`,
kebab,
common: commonVars
}), (renderErr, html) => {
if (renderErr) {
console.error(renderErr);
return;
}
const i18n = new I18nReplacer(lang);
html = html.replace(i18n.pattern, i18n.replacement);
html = fa(html);
const htmlPath = `./built/client/docs/${lang}/api/endpoints/${ep.name}.html`;
mkdirp(path.dirname(htmlPath), (mkdirErr) => {
if (mkdirErr) {
console.error(mkdirErr);
return;
}
fs.writeFileSync(htmlPath, html, 'utf-8');
});
});
});
});
});
});
gulp.task('doc:api:entities', async () => {
const commonVars = await generateVars();
glob('./src/client/docs/api/entities/**/*.yaml', (globErr, files) => {
if (globErr) {
console.error(globErr);
return;
}
files.forEach(file => {
const entity = yaml.safeLoad(fs.readFileSync(file, 'utf-8')) as any;
const vars = {
name: entity.name,
desc: entity.desc,
// WIP type
props: sortParams(entity.props.map((p: any) => parseParam(p))),
propDefs: extractDefs(entity.props),
};
langs.forEach(lang => {
pug.renderFile('./src/client/docs/api/entities/view.pug', Object.assign({}, vars, {
lang,
title: entity.name,
src: `https://github.com/syuilo/misskey/tree/master/src/client/docs/api/entities/${kebab(entity.name)}.yaml`,
kebab,
common: commonVars
}), (renderErr, html) => {
if (renderErr) {
console.error(renderErr);
return;
}
const i18n = new I18nReplacer(lang);
html = html.replace(i18n.pattern, i18n.replacement);
html = fa(html);
const htmlPath = `./built/client/docs/${lang}/api/entities/${kebab(entity.name)}.html`;
mkdirp(path.dirname(htmlPath), (mkdirErr) => {
if (mkdirErr) {
console.error(mkdirErr);
return;
}
fs.writeFileSync(htmlPath, html, 'utf-8');
});
});
});
});
});
});

View file

@ -1,10 +1,10 @@
mixin propTable(props) mixin propTable(props)
table.props table.props
thead: tr thead: tr
th %i18n:docs.api.props.name% th= i18n('docs.api.props.name')
th %i18n:docs.api.props.type% th= i18n('docs.api.props.type')
th %i18n:docs.api.props.optional% th= i18n('docs.api.props.optional')
th %i18n:docs.api.props.description% th= i18n('docs.api.props.description')
tbody tbody
each prop in props each prop in props
tr tr
@ -31,7 +31,7 @@ mixin propTable(props)
| (Date) | (Date)
td.optional td.optional
if prop.optional if prop.optional
| %i18n:docs.api.props.yes% = i18n('docs.api.props.yes')
else else
| %i18n:docs.api.props.no% = i18n('docs.api.props.no')
td.desc!= prop.desc[lang] || prop.desc['ja'] td.desc!= prop.desc ? prop.desc[lang] || prop.desc['ja'] : null

View file

@ -2,73 +2,14 @@
* Gulp tasks * Gulp tasks
*/ */
import * as fs from 'fs';
import * as path from 'path';
import * as glob from 'glob';
import * as gulp from 'gulp'; import * as gulp from 'gulp';
import * as pug from 'pug';
import * as mkdirp from 'mkdirp';
const stylus = require('gulp-stylus'); const stylus = require('gulp-stylus');
const cssnano = require('gulp-cssnano'); const cssnano = require('gulp-cssnano');
import I18nReplacer from '../../build/i18n';
import fa from '../../build/fa';
import generateVars from './vars';
//require('./api/gulpfile.ts');
gulp.task('doc', [ gulp.task('doc', [
'doc:docs',
//'doc:api',
'doc:styles' 'doc:styles'
]); ]);
gulp.task('doc:docs', async () => {
const commonVars = await generateVars();
glob('./src/client/docs/**/*.*.pug', (globErr, files) => {
if (globErr) {
console.error(globErr);
return;
}
files.forEach(file => {
const [, name, lang] = file.match(/docs\/(.+?)\.(.+?)\.pug$/);
const vars = {
common: commonVars,
lang: lang,
title: fs.readFileSync(file, 'utf-8').match(/^h1 (.+?)\r?\n/)[1],
src: `https://github.com/syuilo/misskey/tree/master/src/client/docs/${name}.${lang}.pug`,
};
pug.renderFile(file, vars, (renderErr, content) => {
if (renderErr) {
console.error(renderErr);
return;
}
pug.renderFile('./src/client/docs/layout.pug', Object.assign({}, vars, {
content
}), (renderErr2, html) => {
if (renderErr2) {
console.error(renderErr2);
return;
}
const i18n = new I18nReplacer(lang);
html = html.replace(i18n.pattern, i18n.replacement);
html = fa(html);
const htmlPath = `./built/client/docs/${lang}/${name}.html`;
mkdirp(path.dirname(htmlPath), (mkdirErr) => {
if (mkdirErr) {
console.error(mkdirErr);
return;
}
fs.writeFileSync(htmlPath, html, 'utf-8');
});
});
});
});
});
});
gulp.task('doc:styles', () => gulp.task('doc:styles', () =>
gulp.src('./src/client/docs/**/*.styl') gulp.src('./src/client/docs/**/*.styl')
.pipe(stylus()) .pipe(stylus())

View file

@ -9,6 +9,7 @@ import { Context } from 'cafy';
import ObjectContext from 'cafy/built/types/object'; import ObjectContext from 'cafy/built/types/object';
import config from '../../config'; import config from '../../config';
import generateVars from '../../client/docs/vars'; import generateVars from '../../client/docs/vars';
import I18n from '../../build/i18n';
const docs = `${__dirname}/../../client/docs/`; const docs = `${__dirname}/../../client/docs/`;
@ -63,6 +64,7 @@ router.get('/assets/*', async ctx => {
}); });
router.get('/*/api/endpoints/*', async ctx => { router.get('/*/api/endpoints/*', async ctx => {
const lang = ctx.params[0];
const ep = require('../../../built/server/api/endpoints/' + ctx.params[1]).meta; const ep = require('../../../built/server/api/endpoints/' + ctx.params[1]).meta;
const vars = { const vars = {
@ -76,14 +78,16 @@ router.get('/*/api/endpoints/*', async ctx => {
params: sortParams(Object.keys(ep.params).map(k => parseEPDefParam(k, ep.params[k]))), params: sortParams(Object.keys(ep.params).map(k => parseEPDefParam(k, ep.params[k]))),
paramDefs: extractDefs(Object.keys(ep.params).map(k => ep.params[k])), paramDefs: extractDefs(Object.keys(ep.params).map(k => ep.params[k])),
}; };
console.log(vars);
const commonVars = await generateVars(); const commonVars = await generateVars();
const i18n = new I18n(lang);
await ctx.render('../../../../src/client/docs/api/endpoints/view', Object.assign({}, vars, { await ctx.render('../../../../src/client/docs/api/endpoints/view', Object.assign({}, vars, {
lang: 'ja', lang,
title: ep.name, title: ep.name,
kebab: (string: string) => string.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/\s+/g, '-').toLowerCase(), kebab: (string: string) => string.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/\s+/g, '-').toLowerCase(),
i18n: (key: string) => i18n.get(null, key),
common: commonVars common: commonVars
})); }));
}); });

View file

@ -19,7 +19,7 @@ const constants = require('./src/const.json');
import config from './src/config'; import config from './src/config';
import { licenseHtml } from './src/build/license'; import { licenseHtml } from './src/build/license';
import locales from './locales'; const locales = require('./locales');
const meta = require('./package.json'); const meta = require('./package.json');
const version = meta.clientVersion; const version = meta.clientVersion;
const codename = meta.codename; const codename = meta.codename;