mirror of
https://git.joinsharkey.org/Sharkey/Sharkey.git
synced 2024-11-22 21:43:09 +02:00
feat: Add langPref config option
This commit is contained in:
parent
4f45e72799
commit
8a416cd302
13 changed files with 78 additions and 40 deletions
|
@ -212,5 +212,9 @@ checkActivityPubGetSignature: false
|
||||||
|
|
||||||
#customMOTD: ['Hello World', 'The sharks rule all', 'Shonks']
|
#customMOTD: ['Hello World', 'The sharks rule all', 'Shonks']
|
||||||
|
|
||||||
|
# Prefer these languages for remote notes with language-specific content
|
||||||
|
# Must be valid language codes according to BCP 47
|
||||||
|
#langPref: ['en', 'ja']
|
||||||
|
|
||||||
# Upload or download file size limits (bytes)
|
# Upload or download file size limits (bytes)
|
||||||
#maxFileSize: 262144000
|
#maxFileSize: 262144000
|
||||||
|
|
|
@ -269,5 +269,9 @@ checkActivityPubGetSignature: false
|
||||||
|
|
||||||
#customMOTD: ['Hello World', 'The sharks rule all', 'Shonks']
|
#customMOTD: ['Hello World', 'The sharks rule all', 'Shonks']
|
||||||
|
|
||||||
|
# Prefer these languages for remote notes with language-specific content
|
||||||
|
# Must be valid language codes according to BCP 47
|
||||||
|
#langPref: ['en', 'ja']
|
||||||
|
|
||||||
# Upload or download file size limits (bytes)
|
# Upload or download file size limits (bytes)
|
||||||
#maxFileSize: 262144000
|
#maxFileSize: 262144000
|
||||||
|
|
|
@ -284,6 +284,10 @@ checkActivityPubGetSignature: false
|
||||||
|
|
||||||
#customMOTD: ['Hello World', 'The sharks rule all', 'Shonks']
|
#customMOTD: ['Hello World', 'The sharks rule all', 'Shonks']
|
||||||
|
|
||||||
|
# Prefer these languages for remote notes with language-specific content
|
||||||
|
# Must be valid language codes according to BCP 47
|
||||||
|
#langPref: ['en', 'ja']
|
||||||
|
|
||||||
# Upload or download file size limits (bytes)
|
# Upload or download file size limits (bytes)
|
||||||
#maxFileSize: 262144000
|
#maxFileSize: 262144000
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,8 @@ type Source = {
|
||||||
|
|
||||||
customMOTD?: string[];
|
customMOTD?: string[];
|
||||||
|
|
||||||
|
langPref?: string[];
|
||||||
|
|
||||||
signToActivityPubGet?: boolean;
|
signToActivityPubGet?: boolean;
|
||||||
checkActivityPubGetSignature?: boolean;
|
checkActivityPubGetSignature?: boolean;
|
||||||
|
|
||||||
|
@ -153,6 +155,7 @@ export type Config = {
|
||||||
customMOTD: string[] | undefined;
|
customMOTD: string[] | undefined;
|
||||||
signToActivityPubGet: boolean;
|
signToActivityPubGet: boolean;
|
||||||
checkActivityPubGetSignature: boolean | undefined;
|
checkActivityPubGetSignature: boolean | undefined;
|
||||||
|
langPref: string[];
|
||||||
|
|
||||||
version: string;
|
version: string;
|
||||||
publishTarballInsteadOfProvideRepositoryUrl: boolean;
|
publishTarballInsteadOfProvideRepositoryUrl: boolean;
|
||||||
|
@ -269,6 +272,7 @@ export function loadConfig(): Config {
|
||||||
inboxJobMaxAttempts: config.inboxJobMaxAttempts,
|
inboxJobMaxAttempts: config.inboxJobMaxAttempts,
|
||||||
proxyRemoteFiles: config.proxyRemoteFiles,
|
proxyRemoteFiles: config.proxyRemoteFiles,
|
||||||
customMOTD: config.customMOTD,
|
customMOTD: config.customMOTD,
|
||||||
|
langPref: config.langPref ?? ['en', 'ja'],
|
||||||
signToActivityPubGet: config.signToActivityPubGet ?? true,
|
signToActivityPubGet: config.signToActivityPubGet ?? true,
|
||||||
checkActivityPubGetSignature: config.checkActivityPubGetSignature,
|
checkActivityPubGetSignature: config.checkActivityPubGetSignature,
|
||||||
mediaProxy: externalMediaProxy ?? internalMediaProxy,
|
mediaProxy: externalMediaProxy ?? internalMediaProxy,
|
||||||
|
|
|
@ -25,7 +25,7 @@ import { StatusError } from '@/misc/status-error.js';
|
||||||
import { UtilityService } from '@/core/UtilityService.js';
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { checkHttps } from '@/misc/check-https.js';
|
import { checkHttps } from '@/misc/check-https.js';
|
||||||
import { langmap } from '@/misc/langmap.js';
|
import { langs } from '@/misc/langmap.js';
|
||||||
import { getOneApId, getApId, getOneApHrefNullable, validPost, isEmoji, getApType } from '../type.js';
|
import { getOneApId, getApId, getOneApHrefNullable, validPost, isEmoji, getApType } from '../type.js';
|
||||||
import { ApLoggerService } from '../ApLoggerService.js';
|
import { ApLoggerService } from '../ApLoggerService.js';
|
||||||
import { ApMfmService } from '../ApMfmService.js';
|
import { ApMfmService } from '../ApMfmService.js';
|
||||||
|
@ -241,25 +241,37 @@ export class ApNoteService {
|
||||||
|
|
||||||
const cw = note.summary === '' ? null : note.summary;
|
const cw = note.summary === '' ? null : note.summary;
|
||||||
|
|
||||||
|
let lang: string | null = null;
|
||||||
|
if (note.contentMap != null) {
|
||||||
|
for (const preferredLang of this.config.langPref) {
|
||||||
|
if (note.contentMap[preferredLang]) {
|
||||||
|
lang = preferredLang;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lang) lang = Object.keys(note.contentMap)[0];
|
||||||
|
if (!langs.includes(lang)) lang = null;
|
||||||
|
}
|
||||||
|
|
||||||
// テキストのパース
|
// テキストのパース
|
||||||
let text: string | null = null;
|
let text: string | null = null;
|
||||||
if (note.source?.mediaType === 'text/x.misskeymarkdown' && typeof note.source.content === 'string') {
|
if (note.source?.mediaType === 'text/x.misskeymarkdown' && typeof note.source.content === 'string') {
|
||||||
text = note.source.content;
|
text = note.source.content;
|
||||||
} else if (note.contentMap != null) {
|
} else if (note.contentMap != null && Object.keys(note.contentMap).length !== 0) {
|
||||||
const entry = Object.entries(note.contentMap)[0];
|
let content: string;
|
||||||
text = this.apMfmService.htmlToMfm(entry[1], note.tag);
|
if (lang) {
|
||||||
|
content = note.contentMap[lang];
|
||||||
|
} else {
|
||||||
|
content = Object.values(note.contentMap)[0];
|
||||||
|
}
|
||||||
|
text = this.apMfmService.htmlToMfm(content, note.tag);
|
||||||
} else if (typeof note._misskey_content !== 'undefined') {
|
} else if (typeof note._misskey_content !== 'undefined') {
|
||||||
text = note._misskey_content;
|
text = note._misskey_content;
|
||||||
} else if (typeof note.content === 'string') {
|
} else if (typeof note.content === 'string') {
|
||||||
text = this.apMfmService.htmlToMfm(note.content, note.tag);
|
text = this.apMfmService.htmlToMfm(note.content, note.tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
let lang: string | null = null;
|
|
||||||
if (note.contentMap != null) {
|
|
||||||
const key = Object.keys(note.contentMap)[0];
|
|
||||||
lang = Object.keys(langmap).includes(key) ? key : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// vote
|
// vote
|
||||||
if (reply && reply.hasPoll) {
|
if (reply && reply.hasPoll) {
|
||||||
const poll = await this.pollsRepository.findOneByOrFail({ noteId: reply.id });
|
const poll = await this.pollsRepository.findOneByOrFail({ noteId: reply.id });
|
||||||
|
@ -459,25 +471,37 @@ export class ApNoteService {
|
||||||
|
|
||||||
const cw = note.summary === '' ? null : note.summary;
|
const cw = note.summary === '' ? null : note.summary;
|
||||||
|
|
||||||
|
let lang: string | null = null;
|
||||||
|
if (note.contentMap != null) {
|
||||||
|
for (const preferredLang of this.config.langPref) {
|
||||||
|
if (note.contentMap[preferredLang]) {
|
||||||
|
lang = preferredLang;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lang) lang = Object.keys(note.contentMap)[0];
|
||||||
|
if (!langs.includes(lang)) lang = null;
|
||||||
|
}
|
||||||
|
|
||||||
// テキストのパース
|
// テキストのパース
|
||||||
let text: string | null = null;
|
let text: string | null = null;
|
||||||
if (note.source?.mediaType === 'text/x.misskeymarkdown' && typeof note.source.content === 'string') {
|
if (note.source?.mediaType === 'text/x.misskeymarkdown' && typeof note.source.content === 'string') {
|
||||||
text = note.source.content;
|
text = note.source.content;
|
||||||
} else if (note.contentMap != null) {
|
} else if (note.contentMap != null && Object.keys(note.contentMap).length !== 0) {
|
||||||
const entry = Object.entries(note.contentMap)[0];
|
let content: string;
|
||||||
text = this.apMfmService.htmlToMfm(entry[1], note.tag);
|
if (lang) {
|
||||||
|
content = note.contentMap[lang];
|
||||||
|
} else {
|
||||||
|
content = Object.values(note.contentMap)[0];
|
||||||
|
}
|
||||||
|
text = this.apMfmService.htmlToMfm(content, note.tag);
|
||||||
} else if (typeof note._misskey_content !== 'undefined') {
|
} else if (typeof note._misskey_content !== 'undefined') {
|
||||||
text = note._misskey_content;
|
text = note._misskey_content;
|
||||||
} else if (typeof note.content === 'string') {
|
} else if (typeof note.content === 'string') {
|
||||||
text = this.apMfmService.htmlToMfm(note.content, note.tag);
|
text = this.apMfmService.htmlToMfm(note.content, note.tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
let lang: string | null = null;
|
|
||||||
if (note.contentMap != null) {
|
|
||||||
const key = Object.keys(note.contentMap)[0];
|
|
||||||
lang = Object.keys(langmap).includes(key) ? key : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// vote
|
// vote
|
||||||
if (reply && reply.hasPoll) {
|
if (reply && reply.hasPoll) {
|
||||||
const poll = await this.pollsRepository.findOneByOrFail({ noteId: reply.id });
|
const poll = await this.pollsRepository.findOneByOrFail({ noteId: reply.id });
|
||||||
|
|
|
@ -385,3 +385,4 @@ export const iso639Regional = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const langmap = Object.assign({}, langmapNoRegion, iso639Regional);
|
export const langmap = Object.assign({}, langmapNoRegion, iso639Regional);
|
||||||
|
export const langs = Object.keys(langmap);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
import { langmap } from '@/misc/langmap.js';
|
import { langs } from '@/misc/langmap.js';
|
||||||
|
|
||||||
export const packedNoteSchema = {
|
export const packedNoteSchema = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
|
@ -29,7 +29,7 @@ export const packedNoteSchema = {
|
||||||
},
|
},
|
||||||
lang: {
|
lang: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
enum: [...Object.keys(langmap)],
|
enum: langs,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
},
|
},
|
||||||
cw: {
|
cw: {
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { birthdaySchema, listenbrainzSchema, descriptionSchema, locationSchema,
|
||||||
import type { MiUserProfile } from '@/models/UserProfile.js';
|
import type { MiUserProfile } from '@/models/UserProfile.js';
|
||||||
import { notificationTypes } from '@/types.js';
|
import { notificationTypes } from '@/types.js';
|
||||||
import { normalizeForSearch } from '@/misc/normalize-for-search.js';
|
import { normalizeForSearch } from '@/misc/normalize-for-search.js';
|
||||||
import { langmap } from '@/misc/langmap.js';
|
import { langs } from '@/misc/langmap.js';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
|
@ -149,7 +149,7 @@ export const paramDef = {
|
||||||
location: { ...locationSchema, nullable: true },
|
location: { ...locationSchema, nullable: true },
|
||||||
birthday: { ...birthdaySchema, nullable: true },
|
birthday: { ...birthdaySchema, nullable: true },
|
||||||
listenbrainz: { ...listenbrainzSchema, nullable: true },
|
listenbrainz: { ...listenbrainzSchema, nullable: true },
|
||||||
lang: { type: 'string', enum: [null, ...Object.keys(langmap)] as string[], nullable: true },
|
lang: { type: 'string', enum: [null, ...langs] as string[], nullable: true },
|
||||||
avatarId: { type: 'string', format: 'misskey:id', nullable: true },
|
avatarId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||||
avatarDecorations: { type: 'array', maxItems: 16, items: {
|
avatarDecorations: { type: 'array', maxItems: 16, items: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
|
|
|
@ -20,7 +20,7 @@ import { isPureRenote } from '@/misc/is-pure-renote.js';
|
||||||
import { MetaService } from '@/core/MetaService.js';
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
import { UtilityService } from '@/core/UtilityService.js';
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
import { langmap } from '@/misc/langmap.js';
|
import { langs } from '@/misc/langmap.js';
|
||||||
import { ApiError } from '../../error.js';
|
import { ApiError } from '../../error.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
|
@ -137,7 +137,7 @@ export const paramDef = {
|
||||||
visibleUserIds: { type: 'array', uniqueItems: true, items: {
|
visibleUserIds: { type: 'array', uniqueItems: true, items: {
|
||||||
type: 'string', format: 'misskey:id',
|
type: 'string', format: 'misskey:id',
|
||||||
} },
|
} },
|
||||||
lang: { type: 'string', enum: Object.keys(langmap), nullable: true, maxLength: 10 },
|
lang: { type: 'string', enum: langs, nullable: true, maxLength: 10 },
|
||||||
cw: { type: 'string', nullable: true, minLength: 1, maxLength: 500 },
|
cw: { type: 'string', nullable: true, minLength: 1, maxLength: 500 },
|
||||||
localOnly: { type: 'boolean', default: false },
|
localOnly: { type: 'boolean', default: false },
|
||||||
reactionAcceptance: { type: 'string', nullable: true, enum: [null, 'likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote'], default: null },
|
reactionAcceptance: { type: 'string', nullable: true, enum: [null, 'likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote'], default: null },
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
import { NoteEditService } from '@/core/NoteEditService.js';
|
import { NoteEditService } from '@/core/NoteEditService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
import { langmap } from '@/misc/langmap.js';
|
import { langs } from '@/misc/langmap.js';
|
||||||
import { ApiError } from '../../error.js';
|
import { ApiError } from '../../error.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
|
@ -165,7 +165,7 @@ export const paramDef = {
|
||||||
format: 'misskey:id',
|
format: 'misskey:id',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
lang: { type: 'string', enum: Object.keys(langmap), nullable: true, maxLength: 10 },
|
lang: { type: 'string', enum: langs, nullable: true, maxLength: 10 },
|
||||||
cw: { type: 'string', nullable: true, minLength: 1, maxLength: 500 },
|
cw: { type: 'string', nullable: true, minLength: 1, maxLength: 500 },
|
||||||
localOnly: { type: 'boolean', default: false },
|
localOnly: { type: 'boolean', default: false },
|
||||||
reactionAcceptance: { type: 'string', nullable: true, enum: [null, 'likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote'], default: null },
|
reactionAcceptance: { type: 'string', nullable: true, enum: [null, 'likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote'], default: null },
|
||||||
|
|
|
@ -134,7 +134,7 @@ import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { claimAchievement } from '@/scripts/achievements.js';
|
import { claimAchievement } from '@/scripts/achievements.js';
|
||||||
import { emojiPicker } from '@/scripts/emoji-picker.js';
|
import { emojiPicker } from '@/scripts/emoji-picker.js';
|
||||||
import { mfmFunctionPicker } from '@/scripts/mfm-function-picker.js';
|
import { mfmFunctionPicker } from '@/scripts/mfm-function-picker.js';
|
||||||
import { langmap } from '@/scripts/langmap.js';
|
import { langmap, langs } from '@/scripts/langmap.js';
|
||||||
import { MenuItem } from '@/types/menu.js';
|
import { MenuItem } from '@/types/menu.js';
|
||||||
|
|
||||||
const $i = signinRequired();
|
const $i = signinRequired();
|
||||||
|
@ -547,7 +547,6 @@ async function toggleReactionAcceptance() {
|
||||||
|
|
||||||
function attemptNormalizeLang(lang: string | null) {
|
function attemptNormalizeLang(lang: string | null) {
|
||||||
if (lang == null) return null;
|
if (lang == null) return null;
|
||||||
const langs = Object.keys(langmap);
|
|
||||||
if (!langs[lang]) lang = lang.split('-')[0];
|
if (!langs[lang]) lang = lang.split('-')[0];
|
||||||
return lang;
|
return lang;
|
||||||
}
|
}
|
||||||
|
@ -562,8 +561,6 @@ function setLanguage(ev: MouseEvent) {
|
||||||
action: () => {},
|
action: () => {},
|
||||||
});
|
});
|
||||||
|
|
||||||
const langs = Object.keys(langmap);
|
|
||||||
|
|
||||||
// Show recently used language first
|
// Show recently used language first
|
||||||
let recentlyUsedLanguagesExist = false;
|
let recentlyUsedLanguagesExist = false;
|
||||||
for (const lang of defaultStore.state.recentlyUsedPostLanguages) {
|
for (const lang of defaultStore.state.recentlyUsedPostLanguages) {
|
||||||
|
@ -959,11 +956,10 @@ async function post(ev?: MouseEvent) {
|
||||||
|
|
||||||
// update recentlyUsedLanguages
|
// update recentlyUsedLanguages
|
||||||
if (language.value != null) {
|
if (language.value != null) {
|
||||||
const languages = Object.keys(langmap);
|
|
||||||
const maxLength = 6;
|
const maxLength = 6;
|
||||||
|
|
||||||
defaultStore.set('recentlyUsedPostLanguages', [language.value].concat(defaultStore.state.recentlyUsedPostLanguages.filter((lang) => {
|
defaultStore.set('recentlyUsedPostLanguages', [language.value].concat(defaultStore.state.recentlyUsedPostLanguages.filter((lang) => {
|
||||||
return (lang !== language.value && languages.includes(lang));
|
return (lang !== language.value && langs.includes(lang));
|
||||||
})).slice(0, maxLength));
|
})).slice(0, maxLength));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<MkSelect v-model="profile.lang">
|
<MkSelect v-model="profile.lang">
|
||||||
<template #label>{{ i18n.ts.language }}</template>
|
<template #label>{{ i18n.ts.language }}</template>
|
||||||
<option v-for="x in Object.keys(langmap)" :key="x" :value="x">{{ langmap[x].nativeName }}</option>
|
<option v-for="x in langs" :key="x" :value="x">{{ langmap[x].nativeName }}</option>
|
||||||
</MkSelect>
|
</MkSelect>
|
||||||
|
|
||||||
<FormSlot>
|
<FormSlot>
|
||||||
|
@ -128,7 +128,7 @@ import { selectFile } from '@/scripts/select-file.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { signinRequired } from '@/account.js';
|
import { signinRequired } from '@/account.js';
|
||||||
import { langmap } from '@/scripts/langmap.js';
|
import { langmap, langs } from '@/scripts/langmap.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { claimAchievement } from '@/scripts/achievements.js';
|
import { claimAchievement } from '@/scripts/achievements.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
|
|
|
@ -385,3 +385,4 @@ export const iso639Regional = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const langmap = Object.assign({}, langmapNoRegion, iso639Regional);
|
export const langmap = Object.assign({}, langmapNoRegion, iso639Regional);
|
||||||
|
export const langs = Object.keys(langmap);
|
||||||
|
|
Loading…
Reference in a new issue