diff --git a/README.md b/README.md
index 1ac4ff602..1ac950010 100644
--- a/README.md
+++ b/README.md
@@ -40,6 +40,7 @@
- マージされていない本家版へのプルリクエストを独断でマージ
- RTL Layout Support ([!10452](https://git.joinfirefish.org/firefish/firefish/-/merge_requests/10452))
+ - Add language picker to post form ([!10616](https://git.joinfirefish.org/firefish/firefish/-/merge_requests/10616))
- `emojis` の API エンドポイント(Misskey v13- 互換)を追加([firefish-mkdir](https://git.mkdir.uk/hiira/firefish-mkdir) から取り込み)
- Docker のベースイメージに Node v21 を使用
- HTML のコードに入るコメントアートを削除
diff --git a/locales/en-US.yml b/locales/en-US.yml
index f1ca55800..40a273837 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -1171,6 +1171,8 @@ pullDownToReload: "Pull down to reload"
enableTimelineStreaming: "Update timelines automatically"
useEmojiCdn: "Get Twemoji from CDN"
useEmojiCdnDescription: "Use Twemoji from the JSDelivr CDN instead of the server's assets."
+suggested: "Suggested"
+noLanguage: "No language"
_sensitiveMediaDetection:
description: "Reduces the effort of server moderation through automatically recognizing
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index d2f33c10c..01a9614da 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -2032,6 +2032,8 @@ _iconSets:
regular: "標準"
fill: "塗りつぶし"
duotone: "2色"
+suggested: "候補"
+noLanguage: "言語なし"
moreUrls: "固定するページ"
moreUrlsDescription: "左下のヘルプメニューに固定したいページを以下の形式で、改行区切りで入力してください:\n\"表示名\": https://example.com/"
releaseToReload: "離して再読み込み"
diff --git a/neko/pnpm-lock.yaml b/neko/pnpm-lock.yaml
index 3655bfbf0..858de71fa 100644
--- a/neko/pnpm-lock.yaml
+++ b/neko/pnpm-lock.yaml
@@ -201,6 +201,9 @@ importers:
file-type:
specifier: 18.7.0
version: 18.7.0
+ firefish-js:
+ specifier: workspace:*
+ version: link:../firefish-js
fluent-ffmpeg:
specifier: 2.1.2
version: 2.1.2
@@ -393,9 +396,6 @@ importers:
tinycolor2:
specifier: 1.6.0
version: 1.6.0
- tinyld:
- specifier: 1.3.4
- version: 1.3.4
tmp:
specifier: 0.2.1
version: 0.2.1
@@ -15760,6 +15760,7 @@ packages:
resolution: {integrity: sha512-u26CNoaInA4XpDU+8s/6Cq8xHc2T5M4fXB3ICfXPokUQoLzmPgSZU02TAkFwFMJCWTjk53gtkS8pETTreZwCqw==}
engines: {node: '>= 12.10.0', npm: '>= 6.12.0', yarn: '>= 1.20.0'}
hasBin: true
+ dev: true
/titleize@3.0.0:
resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==}
diff --git a/packages/backend/package.json b/packages/backend/package.json
index d8e6bb2f6..fa6833088 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -62,6 +62,7 @@
"feed": "4.2.2",
"file-type": "18.7.0",
"fluent-ffmpeg": "2.1.2",
+ "firefish-js": "workspace:*",
"got": "13.0.0",
"gunzip-maybe": "1.4.2",
"happy-dom": "12.10.3",
@@ -125,7 +126,6 @@
"tar-stream": "3.1.6",
"tesseract.js": "5.0.3",
"tinycolor2": "1.6.0",
- "tinyld": "1.3.4",
"tmp": "0.2.1",
"typeorm": "0.3.17",
"ulid": "2.3.0",
diff --git a/packages/backend/src/misc/detect-language.ts b/packages/backend/src/misc/detect-language.ts
deleted file mode 100644
index 6147247de..000000000
--- a/packages/backend/src/misc/detect-language.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { detect } from "tinyld";
-import * as mfm from "mfm-js";
-
-export default function detectLanguage(text: string): string {
- const nodes = mfm.parse(text);
- const filtered = mfm.extract(nodes, (node) => {
- return node.type === "text" || node.type === "quote";
- });
- const purified = mfm.toString(filtered);
- return detect(purified);
-}
diff --git a/packages/backend/src/misc/langmap.ts b/packages/backend/src/misc/langmap.ts
index 106130d3c..c4d4f0beb 100644
--- a/packages/backend/src/misc/langmap.ts
+++ b/packages/backend/src/misc/langmap.ts
@@ -1,217 +1,71 @@
-// TODO: sharedに置いてフロントエンドのと統合したい
-export const langmap = {
- ach: {
- nativeName: "Lwo",
- },
- ady: {
- nativeName: "Адыгэбзэ",
- },
+export const iso639Langs1 = {
af: {
nativeName: "Afrikaans",
},
- "af-NA": {
- nativeName: "Afrikaans (Namibia)",
- },
- "af-ZA": {
- nativeName: "Afrikaans (South Africa)",
- },
ak: {
nativeName: "Tɕɥi",
},
ar: {
nativeName: "العربية",
+ rtl: true,
},
- "ar-AR": {
- nativeName: "العربية",
- },
- "ar-MA": {
- nativeName: "العربية",
- },
- "ar-SA": {
- nativeName: "العربية (السعودية)",
- },
- "ay-BO": {
+ ay: {
nativeName: "Aymar aru",
},
az: {
nativeName: "Azərbaycan dili",
},
- "az-AZ": {
- nativeName: "Azərbaycan dili",
- },
- "be-BY": {
+ be: {
nativeName: "Беларуская",
},
bg: {
nativeName: "Български",
},
- "bg-BG": {
- nativeName: "Български",
- },
bn: {
nativeName: "বাংলা",
},
- "bn-IN": {
- nativeName: "বাংলা (ভারত)",
- },
- "bn-BD": {
- nativeName: "বাংলা(বাংলাদেশ)",
- },
br: {
nativeName: "Brezhoneg",
},
- "bs-BA": {
+ bs: {
nativeName: "Bosanski",
},
ca: {
nativeName: "Català",
},
- "ca-ES": {
- nativeName: "Català",
- },
- cak: {
- nativeName: "Maya Kaqchikel",
- },
- "ck-US": {
- nativeName: "ᏣᎳᎩ (tsalagi)",
- },
cs: {
nativeName: "Čeština",
},
- "cs-CZ": {
- nativeName: "Čeština",
- },
cy: {
nativeName: "Cymraeg",
},
- "cy-GB": {
- nativeName: "Cymraeg",
- },
da: {
nativeName: "Dansk",
},
- "da-DK": {
- nativeName: "Dansk",
- },
de: {
nativeName: "Deutsch",
},
- "de-AT": {
- nativeName: "Deutsch (Österreich)",
- },
- "de-DE": {
- nativeName: "Deutsch (Deutschland)",
- },
- "de-CH": {
- nativeName: "Deutsch (Schweiz)",
- },
- dsb: {
- nativeName: "Dolnoserbšćina",
- },
el: {
nativeName: "Ελληνικά",
},
- "el-GR": {
- nativeName: "Ελληνικά",
- },
en: {
nativeName: "English",
},
- "en-GB": {
- nativeName: "English (UK)",
- },
- "en-AU": {
- nativeName: "English (Australia)",
- },
- "en-CA": {
- nativeName: "English (Canada)",
- },
- "en-IE": {
- nativeName: "English (Ireland)",
- },
- "en-IN": {
- nativeName: "English (India)",
- },
- "en-PI": {
- nativeName: "English (Pirate)",
- },
- "en-SG": {
- nativeName: "English (Singapore)",
- },
- "en-UD": {
- nativeName: "English (Upside Down)",
- },
- "en-US": {
- nativeName: "English (US)",
- },
- "en-ZA": {
- nativeName: "English (South Africa)",
- },
- "en@pirate": {
- nativeName: "English (Pirate)",
- },
eo: {
nativeName: "Esperanto",
},
- "eo-EO": {
- nativeName: "Esperanto",
- },
es: {
nativeName: "Español",
},
- "es-AR": {
- nativeName: "Español (Argentine)",
- },
- "es-419": {
- nativeName: "Español (Latinoamérica)",
- },
- "es-CL": {
- nativeName: "Español (Chile)",
- },
- "es-CO": {
- nativeName: "Español (Colombia)",
- },
- "es-EC": {
- nativeName: "Español (Ecuador)",
- },
- "es-ES": {
- nativeName: "Español (España)",
- },
- "es-LA": {
- nativeName: "Español (Latinoamérica)",
- },
- "es-NI": {
- nativeName: "Español (Nicaragua)",
- },
- "es-MX": {
- nativeName: "Español (México)",
- },
- "es-US": {
- nativeName: "Español (Estados Unidos)",
- },
- "es-VE": {
- nativeName: "Español (Venezuela)",
- },
et: {
nativeName: "eesti keel",
},
- "et-EE": {
- nativeName: "Eesti (Estonia)",
- },
eu: {
nativeName: "Euskara",
},
- "eu-ES": {
- nativeName: "Euskara",
- },
fa: {
nativeName: "فارسی",
- },
- "fa-IR": {
- nativeName: "فارسی",
- },
- "fb-LT": {
- nativeName: "Leet Speak",
+ rtl: true,
},
ff: {
nativeName: "Fulah",
@@ -219,154 +73,86 @@ export const langmap = {
fi: {
nativeName: "Suomi",
},
- "fi-FI": {
- nativeName: "Suomi",
- },
fo: {
nativeName: "Føroyskt",
},
- "fo-FO": {
- nativeName: "Føroyskt (Færeyjar)",
- },
fr: {
nativeName: "Français",
},
- "fr-CA": {
- nativeName: "Français (Canada)",
- },
- "fr-FR": {
- nativeName: "Français (France)",
- },
- "fr-BE": {
- nativeName: "Français (Belgique)",
- },
- "fr-CH": {
- nativeName: "Français (Suisse)",
- },
- "fy-NL": {
+ fy: {
nativeName: "Frysk",
},
ga: {
nativeName: "Gaeilge",
},
- "ga-IE": {
- nativeName: "Gaeilge",
- },
gd: {
nativeName: "Gàidhlig",
},
gl: {
nativeName: "Galego",
},
- "gl-ES": {
- nativeName: "Galego",
- },
- "gn-PY": {
+ gn: {
nativeName: "Avañe'ẽ",
},
- "gu-IN": {
+ gu: {
nativeName: "ગુજરાતી",
},
gv: {
nativeName: "Gaelg",
},
- "gx-GR": {
- nativeName: "Ἑλληνική ἀρχαία",
- },
he: {
nativeName: "עברית",
- },
- "he-IL": {
- nativeName: "עברית",
+ rtl: true,
},
hi: {
nativeName: "हिन्दी",
},
- "hi-IN": {
- nativeName: "हिन्दी",
- },
hr: {
nativeName: "Hrvatski",
},
- "hr-HR": {
- nativeName: "Hrvatski",
- },
- hsb: {
- nativeName: "Hornjoserbšćina",
- },
ht: {
nativeName: "Kreyòl",
},
hu: {
nativeName: "Magyar",
},
- "hu-HU": {
- nativeName: "Magyar",
- },
hy: {
nativeName: "Հայերեն",
},
- "hy-AM": {
- nativeName: "Հայերեն (Հայաստան)",
- },
id: {
nativeName: "Bahasa Indonesia",
},
- "id-ID": {
- nativeName: "Bahasa Indonesia",
- },
is: {
nativeName: "Íslenska",
},
- "is-IS": {
- nativeName: "Íslenska (Iceland)",
- },
it: {
nativeName: "Italiano",
},
- "it-IT": {
- nativeName: "Italiano",
- },
ja: {
nativeName: "日本語",
},
- "ja-JP": {
- nativeName: "日本語 (日本)",
- },
- "jv-ID": {
+ jv: {
nativeName: "Basa Jawa",
},
- "ka-GE": {
+ ka: {
nativeName: "ქართული",
},
- "kk-KZ": {
+ kk: {
nativeName: "Қазақша",
},
- km: {
- nativeName: "ភាសាខ្មែរ",
- },
kl: {
nativeName: "kalaallisut",
},
- "km-KH": {
+ km: {
nativeName: "ភាសាខ្មែរ",
},
- kab: {
- nativeName: "Taqbaylit",
- },
kn: {
nativeName: "ಕನ್ನಡ",
},
- "kn-IN": {
- nativeName: "ಕನ್ನಡ (India)",
- },
ko: {
nativeName: "한국어",
},
- "ko-KR": {
- nativeName: "한국어 (한국)",
- },
- "ku-TR": {
+ ku: {
nativeName: "Kurdî",
},
kw: {
@@ -375,66 +161,39 @@ export const langmap = {
la: {
nativeName: "Latin",
},
- "la-VA": {
- nativeName: "Latin",
- },
lb: {
nativeName: "Lëtzebuergesch",
},
- "li-NL": {
+ li: {
nativeName: "Lèmbörgs",
},
lt: {
nativeName: "Lietuvių",
},
- "lt-LT": {
- nativeName: "Lietuvių",
- },
lv: {
nativeName: "Latviešu",
},
- "lv-LV": {
- nativeName: "Latviešu",
- },
- mai: {
- nativeName: "मैथिली, মৈথিলী",
- },
- "mg-MG": {
+ mg: {
nativeName: "Malagasy",
},
mk: {
nativeName: "Македонски",
},
- "mk-MK": {
- nativeName: "Македонски (Македонски)",
- },
ml: {
nativeName: "മലയാളം",
},
- "ml-IN": {
- nativeName: "മലയാളം",
- },
- "mn-MN": {
+ mn: {
nativeName: "Монгол",
},
mr: {
nativeName: "मराठी",
},
- "mr-IN": {
- nativeName: "मराठी",
- },
ms: {
nativeName: "Bahasa Melayu",
},
- "ms-MY": {
- nativeName: "Bahasa Melayu",
- },
mt: {
nativeName: "Malti",
},
- "mt-MT": {
- nativeName: "Malti",
- },
my: {
nativeName: "ဗမာစကာ",
},
@@ -444,223 +203,179 @@ export const langmap = {
nb: {
nativeName: "Norsk (bokmål)",
},
- "nb-NO": {
- nativeName: "Norsk (bokmål)",
- },
ne: {
nativeName: "नेपाली",
},
- "ne-NP": {
- nativeName: "नेपाली",
- },
nl: {
nativeName: "Nederlands",
},
- "nl-BE": {
- nativeName: "Nederlands (België)",
- },
- "nl-NL": {
- nativeName: "Nederlands (Nederland)",
- },
- "nn-NO": {
+ nn: {
nativeName: "Norsk (nynorsk)",
},
oc: {
nativeName: "Occitan",
},
- "or-IN": {
+ or: {
nativeName: "ଓଡ଼ିଆ",
},
pa: {
nativeName: "ਪੰਜਾਬੀ",
},
- "pa-IN": {
- nativeName: "ਪੰਜਾਬੀ (ਭਾਰਤ ਨੂੰ)",
- },
pl: {
nativeName: "Polski",
},
- "pl-PL": {
- nativeName: "Polski",
- },
- "ps-AF": {
+ ps: {
nativeName: "پښتو",
+ rtl: true,
},
pt: {
nativeName: "Português",
},
- "pt-BR": {
- nativeName: "Português (Brasil)",
- },
- "pt-PT": {
- nativeName: "Português (Portugal)",
- },
- "qu-PE": {
+ qu: {
nativeName: "Qhichwa",
},
- "rm-CH": {
+ rm: {
nativeName: "Rumantsch",
},
ro: {
nativeName: "Română",
},
- "ro-RO": {
- nativeName: "Română",
- },
ru: {
nativeName: "Русский",
},
- "ru-RU": {
- nativeName: "Русский",
- },
- "sa-IN": {
+ sa: {
nativeName: "संस्कृतम्",
},
- "se-NO": {
+ se: {
nativeName: "Davvisámegiella",
},
sh: {
nativeName: "српскохрватски",
},
- "si-LK": {
+ si: {
nativeName: "සිංහල",
},
sk: {
nativeName: "Slovenčina",
},
- "sk-SK": {
- nativeName: "Slovenčina (Slovakia)",
- },
sl: {
nativeName: "Slovenščina",
},
- "sl-SI": {
- nativeName: "Slovenščina",
- },
- "so-SO": {
+ so: {
nativeName: "Soomaaliga",
},
sq: {
nativeName: "Shqip",
},
- "sq-AL": {
- nativeName: "Shqip",
- },
sr: {
nativeName: "Српски",
},
- "sr-RS": {
- nativeName: "Српски (Serbia)",
- },
su: {
nativeName: "Basa Sunda",
},
sv: {
nativeName: "Svenska",
},
- "sv-SE": {
- nativeName: "Svenska",
- },
sw: {
nativeName: "Kiswahili",
},
- "sw-KE": {
- nativeName: "Kiswahili",
- },
ta: {
nativeName: "தமிழ்",
},
- "ta-IN": {
- nativeName: "தமிழ்",
- },
te: {
nativeName: "తెలుగు",
},
- "te-IN": {
- nativeName: "తెలుగు",
- },
tg: {
nativeName: "забо́ни тоҷикӣ́",
},
- "tg-TJ": {
- nativeName: "тоҷикӣ",
- },
th: {
nativeName: "ภาษาไทย",
},
- "th-TH": {
- nativeName: "ภาษาไทย (ประเทศไทย)",
- },
- fil: {
- nativeName: "Filipino",
- },
- tlh: {
- nativeName: "tlhIngan-Hol",
- },
tr: {
nativeName: "Türkçe",
},
- "tr-TR": {
- nativeName: "Türkçe",
- },
- "tt-RU": {
+ tt: {
nativeName: "татарча",
},
uk: {
nativeName: "Українська",
},
- "uk-UA": {
- nativeName: "Українська",
- },
ur: {
nativeName: "اردو",
- },
- "ur-PK": {
- nativeName: "اردو",
+ rtl: true,
},
uz: {
nativeName: "O'zbek",
},
- "uz-UZ": {
- nativeName: "O'zbek",
- },
vi: {
nativeName: "Tiếng Việt",
},
- "vi-VN": {
- nativeName: "Tiếng Việt",
- },
- "xh-ZA": {
+ xh: {
nativeName: "isiXhosa",
},
yi: {
nativeName: "ייִדיש",
- },
- "yi-DE": {
- nativeName: "ייִדיש (German)",
+ rtl: true,
},
zh: {
nativeName: "中文",
},
- "zh-Hans": {
- nativeName: "中文简体",
- },
- "zh-Hant": {
- nativeName: "中文繁體",
- },
- "zh-CN": {
- nativeName: "中文(中国大陆)",
- },
- "zh-HK": {
- nativeName: "中文(香港)",
- },
- "zh-SG": {
- nativeName: "中文(新加坡)",
- },
- "zh-TW": {
- nativeName: "中文(台灣)",
- },
- "zu-ZA": {
+ zu: {
nativeName: "isiZulu",
},
};
+
+export const iso639Langs3 = {
+ ach: {
+ nativeName: "Lwo",
+ },
+ ady: {
+ nativeName: "Адыгэбзэ",
+ },
+ cak: {
+ nativeName: "Maya Kaqchikel",
+ },
+ chr: {
+ nativeName: "ᏣᎳᎩ (tsalagi)",
+ },
+ dsb: {
+ nativeName: "Dolnoserbšćina",
+ },
+ fil: {
+ nativeName: "Filipino",
+ },
+ hsb: {
+ nativeName: "Hornjoserbšćina",
+ },
+ kab: {
+ nativeName: "Taqbaylit",
+ },
+ mai: {
+ nativeName: "मैथिली, মৈথিলী",
+ },
+ tlh: {
+ nativeName: "tlhIngan-Hol",
+ },
+ tok: {
+ nativeName: "Toki Pona",
+ },
+ yue: {
+ nativeName: "粵語",
+ },
+ nan: {
+ nativeName: "閩南語",
+ },
+};
+
+export const langmapNoRegion = Object.assign({}, iso639Langs1, iso639Langs3);
+
+export const iso639Regional = {
+ "zh-hans": {
+ nativeName: "中文(简体)",
+ },
+ "zh-hant": {
+ nativeName: "中文(繁體)",
+ },
+};
+
+export const langmap = Object.assign({}, langmapNoRegion, iso639Regional);
diff --git a/packages/backend/src/models/schema/note.ts b/packages/backend/src/models/schema/note.ts
index e17f054e8..7dcdbc9b0 100644
--- a/packages/backend/src/models/schema/note.ts
+++ b/packages/backend/src/models/schema/note.ts
@@ -1,3 +1,5 @@
+import { langmap } from "@/misc/langmap.js";
+
export const packedNoteSchema = {
type: "object",
properties: {
@@ -19,6 +21,11 @@ export const packedNoteSchema = {
optional: false,
nullable: true,
},
+ lang: {
+ type: "string",
+ enum: [...Object.keys(langmap)],
+ nullable: true,
+ },
cw: {
type: "string",
optional: true,
diff --git a/packages/backend/src/remote/activitypub/models/note.ts b/packages/backend/src/remote/activitypub/models/note.ts
index 575b19fb8..4b05ef7f7 100644
--- a/packages/backend/src/remote/activitypub/models/note.ts
+++ b/packages/backend/src/remote/activitypub/models/note.ts
@@ -309,16 +309,13 @@ export async function createNote(
) {
text = note.source.content;
if (note.contentMap != null) {
- const key = Object.keys(note.contentMap)[0];
- lang = Object.keys(langmap).includes(key)
- ? key.trim().split("-")[0].split("@")[0]
- : null;
+ const key = Object.keys(note.contentMap)[0].toLowerCase();
+ lang = Object.keys(langmap).includes(key) ? key : null;
}
} else if (note.contentMap != null) {
const entry = Object.entries(note.contentMap)[0];
- lang = Object.keys(langmap).includes(entry[0])
- ? entry[0].trim().split("-")[0].split("@")[0]
- : null;
+ const key = entry[0].toLowerCase();
+ lang = Object.keys(langmap).includes(key) ? key : null;
text = htmlToMfm(entry[1], note.tag);
} else if (typeof note.content === "string") {
text = htmlToMfm(note.content, note.tag);
@@ -584,15 +581,12 @@ export async function updateNote(value: string | IObject, resolver?: Resolver) {
text = post.source.content;
if (post.contentMap != null) {
const key = Object.keys(post.contentMap)[0];
- lang = Object.keys(langmap).includes(key)
- ? key.trim().split("-")[0].split("@")[0]
- : null;
+ lang = Object.keys(langmap).includes(key) ? key : null;
}
} else if (post.contentMap != null) {
const entry = Object.entries(post.contentMap)[0];
- lang = Object.keys(langmap).includes(entry[0])
- ? entry[0].trim().split("-")[0].split("@")[0]
- : null;
+ const key = entry[0].toLowerCase();
+ lang = Object.keys(langmap).includes(key) ? key : null;
text = htmlToMfm(entry[1], post.tag);
} else if (typeof post.content === "string") {
text = htmlToMfm(post.content, post.tag);
diff --git a/packages/backend/src/remote/activitypub/renderer/note.ts b/packages/backend/src/remote/activitypub/renderer/note.ts
index c1beb7604..ffa4b2f37 100644
--- a/packages/backend/src/remote/activitypub/renderer/note.ts
+++ b/packages/backend/src/remote/activitypub/renderer/note.ts
@@ -6,7 +6,6 @@ import { DriveFiles, Notes, Users, Emojis, Polls } from "@/models/index.js";
import type { Emoji } from "@/models/entities/emoji.js";
import type { Poll } from "@/models/entities/poll.js";
import toHtml from "@/remote/activitypub/misc/get-note-html.js";
-import detectLanguage from "@/misc/detect-language.js";
import renderEmoji from "./emoji.js";
import renderMention from "./mention.js";
import renderHashtag from "./hashtag.js";
@@ -115,10 +114,9 @@ export default async function renderNote(
}),
);
- const lang = note.lang ?? detectLanguage(text);
- const contentMap = lang
+ const contentMap = note.lang
? {
- [lang]: content,
+ [note.lang]: content,
}
: null;
diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts
index 082108383..7b900a74a 100644
--- a/packages/backend/src/server/api/endpoints/i/update.ts
+++ b/packages/backend/src/server/api/endpoints/i/update.ts
@@ -90,7 +90,7 @@ export const paramDef = {
birthday: { ...Users.birthdaySchema, nullable: true },
lang: {
type: "string",
- enum: [null, ...Object.keys(langmap)],
+ enum: Object.keys(langmap),
nullable: true,
},
avatarId: { type: "string", format: "misskey:id", nullable: true },
diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts
index 0465d09ec..7a4171dc5 100644
--- a/packages/backend/src/server/api/endpoints/notes/create.ts
+++ b/packages/backend/src/server/api/endpoints/notes/create.ts
@@ -1,5 +1,6 @@
import { In } from "typeorm";
import create from "@/services/note/create.js";
+import { langmap } from "@/misc/langmap.js";
import type { User } from "@/models/entities/user.js";
import {
Users,
@@ -108,7 +109,11 @@ export const paramDef = {
},
},
text: { type: "string", maxLength: MAX_NOTE_TEXT_LENGTH, nullable: true },
- lang: { type: "string", nullable: true, maxLength: 10 },
+ lang: {
+ type: "string",
+ enum: Object.keys(langmap),
+ nullable: true,
+ },
cw: { type: "string", nullable: true, maxLength: 100 },
localOnly: { type: "boolean", default: false },
noExtractMentions: { type: "boolean", default: false },
diff --git a/packages/backend/src/server/api/endpoints/notes/edit.ts b/packages/backend/src/server/api/endpoints/notes/edit.ts
index a0869e410..fdb6ede38 100644
--- a/packages/backend/src/server/api/endpoints/notes/edit.ts
+++ b/packages/backend/src/server/api/endpoints/notes/edit.ts
@@ -35,7 +35,6 @@ import renderUpdate from "@/remote/activitypub/renderer/update.js";
import { deliverToRelays } from "@/services/relay.js";
// import { deliverQuestionUpdate } from "@/services/note/polls/update.js";
import { langmap } from "@/misc/langmap.js";
-import detectLanguage from "@/misc/detect-language.js";
export const meta = {
tags: ["notes"],
@@ -170,7 +169,11 @@ export const paramDef = {
},
},
text: { type: "string", maxLength: MAX_NOTE_TEXT_LENGTH, nullable: true },
- lang: { type: "string", nullable: true, maxLength: 10 },
+ lang: {
+ type: "string",
+ enum: Object.keys(langmap),
+ nullable: true,
+ },
cw: { type: "string", nullable: true, maxLength: 250 },
localOnly: { type: "boolean", default: false },
noExtractMentions: { type: "boolean", default: false },
@@ -378,11 +381,9 @@ export default define(meta, paramDef, async (ps, user) => {
}
if (ps.lang) {
- if (!Object.keys(langmap).includes(ps.lang.trim()))
+ if (!Object.keys(langmap).includes(ps.lang.toLowerCase()))
throw new Error("invalid param");
- ps.lang = ps.lang.trim().split("-")[0].split("@")[0];
- } else if (ps.text) {
- ps.lang = detectLanguage(ps.text);
+ ps.lang = ps.lang.toLowerCase();
} else {
ps.lang = null;
}
diff --git a/packages/backend/src/services/note/create.ts b/packages/backend/src/services/note/create.ts
index ecf588cdc..1bc99d71f 100644
--- a/packages/backend/src/services/note/create.ts
+++ b/packages/backend/src/services/note/create.ts
@@ -63,7 +63,6 @@ import meilisearch from "@/db/meilisearch.js";
import { redisClient } from "@/db/redis.js";
import { Mutex } from "redis-semaphore";
import { langmap } from "@/misc/langmap.js";
-import detectLanguage from "@/misc/detect-language.js";
const mutedWordsCache = new Cache<
{ userId: UserProfile["userId"]; mutedWords: UserProfile["mutedWords"] }[]
@@ -276,11 +275,9 @@ export default async (
}
if (data.lang) {
- if (!Object.keys(langmap).includes(data.lang.trim()))
+ if (!Object.keys(langmap).includes(data.lang.toLowerCase()))
throw new Error("invalid param");
- data.lang = data.lang.trim().split("-")[0].split("@")[0];
- } else if (data.text) {
- data.lang = detectLanguage(data.text);
+ data.lang = data.lang.toLowerCase();
} else {
data.lang = null;
}
diff --git a/packages/client/src/components/MkPostForm.vue b/packages/client/src/components/MkPostForm.vue
index 917eee7ea..65528e248 100644
--- a/packages/client/src/components/MkPostForm.vue
+++ b/packages/client/src/components/MkPostForm.vue
@@ -54,6 +54,21 @@
>
+