diff --git a/docs/api-change.md b/docs/api-change.md
index f5254955f2..2ffbf3a826 100644
--- a/docs/api-change.md
+++ b/docs/api-change.md
@@ -2,6 +2,8 @@
 
 Breaking changes are indicated by the :warning: icon.
 
+- Adding `lang` from the response of `i` and the request parameter of `i/update`.
+
 ## v20240504
 
 - :warning: Removed `release` endpoint.
diff --git a/docs/downgrade.sql b/docs/downgrade.sql
index 787785eb67..6f3901006f 100644
--- a/docs/downgrade.sql
+++ b/docs/downgrade.sql
@@ -764,9 +764,6 @@ CREATE SEQUENCE public.__chart_day__users_id_seq
     CACHE 1;
 ALTER SEQUENCE public.__chart_day__users_id_seq OWNED BY public.__chart_day__users.id;
 
--- drop-user-profile-language
-ALTER TABLE "user_profile" ADD COLUMN "lang" character varying(32);
-
 -- emoji-moderator
 ALTER TABLE "user" DROP COLUMN "emojiModPerm";
 DROP TYPE "public"."user_emojimodperm_enum";
diff --git a/locales/en-US.yml b/locales/en-US.yml
index 08fcc490ea..d5b81b0be1 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -766,6 +766,9 @@ confirmToUnclipAlreadyClippedNote: "This post is already part of the \"{name}\"
 public: "Public"
 i18nInfo: "Firefish is being translated into various languages by volunteers. You
   can help at {link}."
+i18nServerInfo: "New clients will be in {language} by default."
+i18nServerChange: "Use {language} instead."
+i18nServerSet: "Use {language} for new clients."
 manageAccessTokens: "Manage access tokens"
 accountInfo: "Account Info"
 notesCount: "Number of posts"
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index ef9f9b9bfb..72b7ed2969 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -685,6 +685,9 @@ unclip: "クリップ解除"
 confirmToUnclipAlreadyClippedNote: "この投稿はすでにクリップ「{name}」に含まれています。投稿をこのクリップから除外しますか?"
 public: "公開"
 i18nInfo: "Firefishは有志によって様々な言語に翻訳されています。{link}で翻訳に協力できます。"
+i18nServerInfo: "新しいクライアントはデフォルトで {language} で表示します。"
+i18nServerChange: "{language} に変更する。"
+i18nServerSet: "新しいクライアントの表示言語も {language} にする。"
 manageAccessTokens: "アクセストークンの管理"
 accountInfo: "アカウント情報"
 notesCount: "投稿の数"
diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml
index 2b326c4066..9744bb95f7 100644
--- a/locales/zh-CN.yml
+++ b/locales/zh-CN.yml
@@ -667,6 +667,9 @@ unclip: "移除便签"
 confirmToUnclipAlreadyClippedNote: "本帖已包含在便签 \"{name}\" 里。您想要将本帖从该便签中移除吗?"
 public: "公开"
 i18nInfo: "Firefish 已经被志愿者们翻译成了各种语言。如果您也有兴趣,可以通过 {link} 帮助翻译。"
+i18nServerInfo: "新客户端将默认使用 {language}。"
+i18nServerChange: "改为 {language}。"
+i18nServerSet: "设定新客户端使用 {language}。"
 manageAccessTokens: "管理访问令牌"
 accountInfo: "账号信息"
 notesCount: "帖子数量"
diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml
index 5a722933e6..556a4efb61 100644
--- a/locales/zh-TW.yml
+++ b/locales/zh-TW.yml
@@ -661,6 +661,9 @@ unclip: "解除摘錄"
 confirmToUnclipAlreadyClippedNote: "此貼文已包含在摘錄「{name}」中。 你想將貼文從這個摘錄中排除嗎?"
 public: "公開"
 i18nInfo: "Firefish已經被志願者們翻譯成各種語言版本,如果想要幫忙的話,可以進入{link}幫助翻譯。"
+i18nServerInfo: "新客戶端將默認使用 {language}。"
+i18nServerChange: "改爲 {language}。"
+i18nServerSet: "設定新客戶端使用 {language}。"
 manageAccessTokens: "管理存取權杖"
 accountInfo: "帳戶資訊"
 notesCount: "貼文數量"
diff --git a/packages/backend/src/migration/1714888400293-add-user-profile-language.ts b/packages/backend/src/migration/1714888400293-add-user-profile-language.ts
new file mode 100644
index 0000000000..8fb6496402
--- /dev/null
+++ b/packages/backend/src/migration/1714888400293-add-user-profile-language.ts
@@ -0,0 +1,13 @@
+import type { MigrationInterface, QueryRunner } from "typeorm";
+
+export class AddUserProfileLanguage1714888400293 implements MigrationInterface {
+	async up(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(
+			`ALTER TABLE "user_profile" ADD COLUMN "lang" character varying(32)`,
+		);
+	}
+
+	async down(queryRunner: QueryRunner): Promise<void> {
+		await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "lang"`);
+	}
+}
diff --git a/packages/backend/src/models/entities/user-profile.ts b/packages/backend/src/models/entities/user-profile.ts
index 2fe2b7a58a..2b9ac79195 100644
--- a/packages/backend/src/models/entities/user-profile.ts
+++ b/packages/backend/src/models/entities/user-profile.ts
@@ -50,6 +50,12 @@ export class UserProfile {
 		verified?: boolean;
 	}[];
 
+	@Column("varchar", {
+		length: 32,
+		nullable: true,
+	})
+	public lang: string | null;
+
 	@Column("varchar", {
 		length: 512,
 		nullable: true,
diff --git a/packages/backend/src/models/repositories/user.ts b/packages/backend/src/models/repositories/user.ts
index a5a8771645..0f4ea9f72a 100644
--- a/packages/backend/src/models/repositories/user.ts
+++ b/packages/backend/src/models/repositories/user.ts
@@ -512,6 +512,7 @@ export const UserRepository = db.getRepository(User).extend({
 						description: profile!.description,
 						location: profile!.location,
 						birthday: profile!.birthday,
+						lang: profile!.lang,
 						fields: profile!.fields,
 						followersCount: followersCount ?? null,
 						followingCount: followingCount ?? null,
diff --git a/packages/backend/src/models/schema/user.ts b/packages/backend/src/models/schema/user.ts
index bcdd718dd1..c7417ce0e4 100644
--- a/packages/backend/src/models/schema/user.ts
+++ b/packages/backend/src/models/schema/user.ts
@@ -204,6 +204,12 @@ export const packedUserDetailedNotMeOnlySchema = {
 			optional: false,
 			example: "2018-03-12",
 		},
+		lang: {
+			type: "string",
+			nullable: true,
+			optional: false,
+			example: "ja-JP",
+		},
 		fields: {
 			type: "array",
 			nullable: false,
diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts
index 9a2b49cb3d..50f0da8f8d 100644
--- a/packages/backend/src/server/api/endpoints/i/update.ts
+++ b/packages/backend/src/server/api/endpoints/i/update.ts
@@ -87,6 +87,7 @@ export const paramDef = {
 		description: { ...Users.descriptionSchema, nullable: true },
 		location: { ...Users.locationSchema, nullable: true },
 		birthday: { ...Users.birthdaySchema, nullable: true },
+		lang: { type: "string", nullable: true },
 		avatarId: { type: "string", format: "misskey:id", nullable: true },
 		bannerId: { type: "string", format: "misskey:id", nullable: true },
 		fields: {
@@ -154,6 +155,7 @@ export default define(meta, paramDef, async (ps, _user, token) => {
 
 	if (ps.name !== undefined) updates.name = ps.name;
 	if (ps.description !== undefined) profileUpdates.description = ps.description;
+	if (typeof ps.lang === "string") profileUpdates.lang = ps.lang;
 	if (ps.location !== undefined) profileUpdates.location = ps.location;
 	if (ps.birthday !== undefined) profileUpdates.birthday = ps.birthday;
 	if (ps.ffVisibility !== undefined)
diff --git a/packages/client/src/account.ts b/packages/client/src/account.ts
index cf6fb54915..fb3f70c34e 100644
--- a/packages/client/src/account.ts
+++ b/packages/client/src/account.ts
@@ -132,6 +132,9 @@ export async function signIn(token: Account["token"], redirect?: string) {
 	if (_DEV_) console.log("logging as token ", token);
 	const newAccount = await fetchAccount(token);
 	localStorage.setItem("account", JSON.stringify(newAccount));
+	if (newAccount.lang) {
+		localStorage.setItem("lang", newAccount.lang);
+	}
 	document.cookie = `token=${token}; path=/; max-age=31536000`; // bull dashboardの認証とかで使う
 	await addAccount(newAccount.id, token);
 
diff --git a/packages/client/src/pages/settings/general.vue b/packages/client/src/pages/settings/general.vue
index f6c5ffc742..0659e2b1c4 100644
--- a/packages/client/src/pages/settings/general.vue
+++ b/packages/client/src/pages/settings/general.vue
@@ -14,6 +14,12 @@
 						>
 					</template>
 				</I18n>
+				<I18n :src="i18n.ts.i18nServerInfo" v-if="serverLang" tag="span">
+					<template #language><strong>{{ langs.find(a => a[0] === serverLang)?.[1] ?? serverLang }}</strong></template>
+				</I18n>
+				<button class="_textButton" @click="updateServerLang" v-if="lang && lang !== serverLang">
+					{{i18n.t(serverLang ? "i18nServerChange" : "i18nServerSet", { language: langs.find(a => a[0] === lang)?.[1] ?? lang })}}
+				</button>
 			</template>
 		</FormSelect>
 
@@ -404,6 +410,7 @@ import { deviceKind } from "@/scripts/device-kind";
 import icon from "@/scripts/icon";
 
 const lang = ref(localStorage.getItem("lang"));
+const serverLang = ref(me?.lang);
 const translateLang = ref(localStorage.getItem("translateLang"));
 const fontSize = ref(localStorage.getItem("fontSize"));
 const useSystemFont = ref(localStorage.getItem("useSystemFont") !== "f");
@@ -559,6 +566,14 @@ const foldNotification = computed(
 // 	});
 // }
 
+function updateServerLang() {
+	os.api("i/update", {
+		lang: lang.value,
+	}).then((i) => {
+		serverLang.value = i.lang;
+	});
+}
+
 watch(swipeOnDesktop, () => {
 	defaultStore.set("swipeOnMobile", true);
 });