fix(auth): support dynamic OSS callbacks and LangBot Account copy (#2428)

* fix(auth): support dynamic OSS callbacks and LangBot Account copy

* style(web): format LangBot Account copy

---------

Co-authored-by: dadachann <185672915+dadachann@users.noreply.github.com>
This commit is contained in:
Hyu
2026-08-13 23:18:01 +08:00
committed by GitHub
parent b121c66f18
commit 5084f2391d
14 changed files with 298 additions and 232 deletions
@@ -15,11 +15,9 @@ from ...service.user import ControlPlaneDirectoryRequiredError, PublicRegistrati
@group.group_class('user', '/api/v1/user')
class UserRouterGroup(group.RouterGroup):
@staticmethod
def _origin(value: str) -> tuple[str, str, int | None] | None:
parsed = urlsplit(value)
if parsed.scheme not in {'http', 'https'} or not parsed.hostname:
return None
return parsed.scheme, parsed.hostname.casefold(), parsed.port
def _is_loopback_host(hostname: str) -> bool:
normalized = hostname.casefold().rstrip('.')
return normalized in {'localhost', '127.0.0.1', '::1'}
def _validate_space_redirect_uri(self, redirect_uri: str, *, bind: bool) -> str:
parsed = urlsplit(redirect_uri)
@@ -38,17 +36,12 @@ class UserRouterGroup(group.RouterGroup):
if query != {'mode': ['bind']}:
raise ValueError('Invalid Space binding redirect_uri')
elif query:
raise ValueError('Invalid Space login redirect_uri')
raise ValueError('Invalid LangBot Account login redirect_uri')
redirect_origin = self._origin(redirect_uri)
api_config = self.ap.instance_config.data.get('api', {})
trusted_origins = {
self._origin(str(api_config.get(config_key, '') or '').strip())
for config_key in ('webui_url', 'webhook_prefix')
}
trusted_origins.discard(None)
if redirect_origin not in trusted_origins:
raise ValueError('Untrusted redirect_uri origin')
# OSS instances can live behind arbitrary domains and gateway ports.
# Accept any HTTPS callback, plus HTTP only for local development.
if parsed.scheme == 'http' and not self._is_loopback_host(parsed.hostname):
raise ValueError('Insecure redirect_uri origin')
return redirect_uri
async def initialize(self) -> None:
@@ -416,7 +409,7 @@ class UserRouterGroup(group.RouterGroup):
'Bind the LangBot Account with the same email as this local Account',
)
except ValueError:
return self.http_status(400, -1, 'Space account binding failed')
return self.http_status(400, -1, 'LangBot Account binding failed')
except Exception:
raise
+4 -4
View File
@@ -114,7 +114,7 @@ class UserService:
if purpose == 'login' and account_uuid is not None:
raise ValueError('Login state cannot be bound to an Account')
if purpose != 'login' and launch_workspace_uuid is not None:
raise ValueError('Launch Workspace state is only valid for Space login')
raise ValueError('Launch Workspace state is only valid for LangBot Account login')
if ttl_seconds <= 0:
raise ValueError('OAuth state lifetime must be positive')
@@ -327,7 +327,7 @@ class UserService:
normalized_email = normalize_email(user_email)
if self._uses_control_plane_directory():
raise ControlPlaneDirectoryRequiredError(
'Cloud invitation registration must use a Space account to preserve control-plane identity'
'Cloud invitation registration must use a LangBot Account to preserve control-plane identity'
)
invitation, _ = await self.ap.workspace_collaboration_service.inspect_invitation(invitation_token)
if invitation.normalized_email != normalized_email:
@@ -394,7 +394,7 @@ class UserService:
# Check if this user has a local password set
if not user_obj.password:
raise ValueError('请使用 Space登录')
raise ValueError('请使用 LangBot登录')
await self._verify_password(user_obj.password, password)
@@ -825,7 +825,7 @@ class UserService:
# Check if this Space account is already bound to another user
existing_space_user = await self.get_user_by_space_account_uuid(space_account_uuid)
if existing_space_user and existing_space_user.normalized_email != normalize_email(user_email):
raise ValueError('This Space account is already bound to another user')
raise ValueError('This LangBot Account is already bound to another user')
# Update local account to Space account
normalized_email = normalize_email(user_email)
+1 -1
View File
@@ -17,4 +17,4 @@ class SpaceAccountBindingRequiredError(AccountEmailMismatchError):
code = 'space_account_binding_required'
def __str__(self) -> str:
return 'This local Account must bind Space from Account settings before Space login'
return 'This local account must bind a LangBot Account from Account settings before LangBot Account login'
+41 -25
View File
@@ -165,34 +165,50 @@ async def test_bind_state_is_account_bound_and_requires_authentication(space_oau
@pytest.mark.asyncio
async def test_redirect_origin_and_callback_path_are_restricted(space_oauth_api):
async def test_redirect_allows_dynamic_https_origin_and_loopback_http(space_oauth_api):
_, client = space_oauth_api
wrong_origin = await client.get(
'/api/v1/user/space/authorize-url',
query_string={'redirect_uri': 'https://evil.example/auth/space/callback'},
headers={'Origin': 'http://localhost'},
)
wrong_path = await client.get(
'/api/v1/user/space/authorize-url',
query_string={'redirect_uri': 'http://localhost/arbitrary'},
headers={'Origin': 'http://localhost'},
)
forged_origin = await client.get(
'/api/v1/user/space/authorize-url',
query_string={'redirect_uri': 'https://evil.example/auth/space/callback'},
headers={'Origin': 'https://evil.example'},
)
forged_host = await client.get(
'/api/v1/user/space/authorize-url',
query_string={'redirect_uri': 'https://evil.example/auth/space/callback'},
headers={'Host': 'evil.example'},
)
responses = [
await client.get(
'/api/v1/user/space/authorize-url',
query_string={'redirect_uri': redirect_uri},
headers={'Origin': 'https://irrelevant.example'},
)
for redirect_uri in (
'https://langbot.example/auth/space/callback',
'https://gateway.example:8443/auth/space/callback',
'https://192.0.2.10/auth/space/callback',
'http://localhost:5300/auth/space/callback',
'http://127.0.0.1:5300/auth/space/callback',
'http://[::1]:5300/auth/space/callback',
)
]
assert (await wrong_origin.get_json())['code'] == 1
assert (await wrong_path.get_json())['code'] == 1
assert (await forged_origin.get_json())['code'] == 1
assert (await forged_host.get_json())['code'] == 1
assert all(response.status_code == 200 for response in responses)
payloads = [await response.get_json() for response in responses]
assert all(payload['code'] == 0 for payload in payloads)
@pytest.mark.asyncio
async def test_redirect_rejects_insecure_remote_origin_and_invalid_callback_shape(space_oauth_api):
_, client = space_oauth_api
responses = [
await client.get(
'/api/v1/user/space/authorize-url',
query_string={'redirect_uri': redirect_uri},
)
for redirect_uri in (
'http://langbot.example/auth/space/callback',
'https://langbot.example/arbitrary',
'https://langbot.example/auth/space/callback?next=https://evil.example',
'https://user@langbot.example/auth/space/callback',
'https://langbot.example/auth/space/callback#fragment',
)
]
payloads = [await response.get_json() for response in responses]
assert all(payload['code'] == 1 for payload in payloads)
@pytest.mark.asyncio
@@ -377,7 +377,7 @@ class TestUserServiceAuthenticate:
service = UserService(ap)
# Execute & Verify
with pytest.raises(ValueError, match='请使用 Space登录'):
with pytest.raises(ValueError, match='请使用 LangBot登录'):
await service.authenticate('space@example.com', 'password')
@@ -726,7 +726,7 @@ class TestUserServiceCreateOrUpdateSpaceUser:
)
service = UserService(ap)
with pytest.raises(ControlPlaneDirectoryRequiredError, match='Space account'):
with pytest.raises(ControlPlaneDirectoryRequiredError, match='LangBot Account'):
await service.register_invited_account('invite-token', 'member@example.com', 'password')
async def test_create_or_update_new_space_user_first_init(self):
+24 -23
View File
@@ -85,18 +85,18 @@ const enUS = {
'Recommended: Use official stable model APIs and cloud services',
loginLocal: 'Login with local account',
loginWithPassword: 'Login with password',
spaceLoginTitle: 'Login with Space',
spaceLoginTitle: 'Login with LangBot Account',
spaceLoginDescription:
'Scan the QR code or visit the link below to authorize',
spaceLoginUserCode: 'Your code',
spaceLoginExpires: 'Code expires in {{seconds}} seconds',
spaceLoginWaiting: 'Waiting for authorization...',
spaceLoginSuccess: 'Authorization successful',
spaceLoginFailed: 'Space login failed',
spaceLoginFailed: 'LangBot Account login failed',
spaceLoginExpired: 'Authorization code expired, please try again',
spaceLoginCancel: 'Cancel',
spaceLoginVisitLink: 'Visit link',
spaceLoginProcessing: 'Logging in with Space',
spaceLoginProcessing: 'Logging in with LangBot Account',
spaceLoginProcessingDescription:
'Please wait while we complete your login...',
spaceLoginSuccessDescription: 'Redirecting to LangBot...',
@@ -105,7 +105,7 @@ const enUS = {
backToLogin: 'Back to Login',
backToHome: 'Back to Home',
spaceAccountCannotChangePassword:
'Space accounts cannot change password here',
'LangBot Accounts cannot change password here',
theme: 'Theme',
changePassword: 'Change Password',
currentPassword: 'Current Password',
@@ -254,8 +254,9 @@ const enUS = {
llmModels: 'LLM Models',
localProvider: 'Local',
localProviderDescription: 'Models configured and managed locally',
spaceProviderDescription: 'Models synced from your Space account',
spaceDisabledForLocalAccount: 'Login with Space to use cloud models',
spaceProviderDescription: 'Models synced from your LangBot Account',
spaceDisabledForLocalAccount:
'Login with LangBot Account to use cloud models',
syncModels: 'Sync',
syncSuccess: 'Sync complete: {{created}} created, {{updated}} updated',
syncError: 'Sync failed: ',
@@ -291,15 +292,15 @@ const enUS = {
langbotModelsDescription: 'Cloud models powered by LangBot Space',
credits: 'Credits',
loginWithSpace: 'Login with LangBot Account',
loginToUseModels: 'Login with Space to use cloud models',
loginToUseModels: 'Login with LangBot Account to use cloud models',
ownerMustBindSpace:
'The Workspace owner must connect Space for LangBot Models.',
'The Workspace owner must connect a LangBot Account for LangBot Models.',
usesOwnerSpaceBilling:
"Uses the Workspace owner's Space billing and credits.",
"Uses the Workspace owner's LangBot Account billing and credits.",
noModels: 'No models configured',
langbotModels: 'LangBot Models',
spaceTrialTooltip:
'Free trial credits available! Login with Space to access cloud models with zero configuration.',
'Free trial credits available! Login with LangBot Account to access cloud models with zero configuration.',
unlockModels: 'Login to use',
editProvider: 'Edit Provider',
addProvider: 'Add Provider',
@@ -1218,13 +1219,13 @@ const enUS = {
adminAccountNote:
'The account you use here will be set as the administrator account',
register: 'Register',
initWithSpace: 'Initialize with Space',
initWithSpace: 'Initialize with LangBot Account',
spaceRecommended:
'Recommended: Use official stable model APIs and cloud services',
spaceInfoTip1:
'Space provides unified account authentication services without uploading any of your sensitive information.',
spaceInfoTip2:
'Logging in with a Space account gives you access to LangBot Models and other cloud services, including free model call credits to help you get started quickly.',
'Logging in with a LangBot Account gives you access to LangBot Models and other cloud services, including free model call credits to help you get started quickly.',
spaceInfoTip3:
'Your login method does not affect other features. You can configure and use models from other sources at any time.',
registerLocal: 'Register local account',
@@ -1281,32 +1282,32 @@ const enUS = {
passwordNotSet: 'Not Set',
passwordSetDescription:
'Password is set, you can login with email and password',
spaceStatus: 'Space Account',
spaceStatus: 'LangBot Account',
spaceBound: 'Bound',
spaceNotBound: 'Not Bound',
spaceBoundDescription:
'Space account bound, official model APIs and cloud services available',
bindSpace: 'Bind Space Account',
'LangBot Account bound, official model APIs and cloud services available',
bindSpace: 'Bind LangBot Account',
bindSpaceDescription: 'Bind to use official model APIs and cloud services',
bindSpaceButton: 'Bind',
bindSpaceConfirmTitle: 'Confirm Binding',
bindSpaceConfirmDescription:
'You are about to bind your local instance to a Space account',
'You are about to bind your local instance to a LangBot Account',
bindSpaceWarning:
'After binding, your login email will be changed from {{localEmail}} to the Space account email.',
bindSpaceSuccess: 'Space account bound successfully',
bindSpaceFailed: 'Failed to bind Space account',
'After binding, your login email will be changed from {{localEmail}} to the LangBot Account email.',
bindSpaceSuccess: 'LangBot Account bound successfully',
bindSpaceFailed: 'Failed to bind LangBot Account',
bindSpaceInvalidState:
'Invalid bind request. Please try again from account settings.',
setPasswordHint: 'Set a password to login with email and password',
spaceEmailMismatch:
'The Space login email does not match the local account email.',
'The LangBot Account login email does not match the local account email.',
space_account_not_registeredTitle: 'Account not registered',
space_account_not_registered:
'No local account is registered for this Space email. Ask the Workspace owner for an invitation.',
space_account_binding_requiredTitle: 'Space connection required',
'No local account is registered for this LangBot Account email. Ask the Workspace owner for an invitation.',
space_account_binding_requiredTitle: 'LangBot Account connection required',
space_account_binding_required:
'This local account must connect Space from Account settings before using Space login.',
'This local account must connect a LangBot Account from Account settings before using LangBot Account login.',
},
workspace: {
title: 'Workspace',
+25 -23
View File
@@ -88,19 +88,19 @@ const esES = {
'Recomendado: Usa API de modelos oficiales estables y servicios en la nube',
loginLocal: 'Iniciar sesión con cuenta local',
loginWithPassword: 'Iniciar sesión con contraseña',
spaceLoginTitle: 'Iniciar sesión con Space',
spaceLoginTitle: 'Iniciar sesión con una cuenta de LangBot',
spaceLoginDescription:
'Escanea el código QR o visita el enlace para autorizar',
spaceLoginUserCode: 'Tu código',
spaceLoginExpires: 'El código expira en {{seconds}} segundos',
spaceLoginWaiting: 'Esperando autorización...',
spaceLoginSuccess: 'Autorización exitosa',
spaceLoginFailed: 'Error de inicio de sesión con Space',
spaceLoginFailed: 'Error de inicio de sesión con una cuenta de LangBot',
spaceLoginExpired:
'El código de autorización ha expirado, por favor inténtalo de nuevo',
spaceLoginCancel: 'Cancelar',
spaceLoginVisitLink: 'Visitar enlace',
spaceLoginProcessing: 'Iniciando sesión con Space',
spaceLoginProcessing: 'Iniciando sesión con una cuenta de LangBot',
spaceLoginProcessingDescription:
'Por favor espera mientras completamos tu inicio de sesión...',
spaceLoginSuccessDescription: 'Redirigiendo a LangBot...',
@@ -109,7 +109,7 @@ const esES = {
backToLogin: 'Volver al inicio de sesión',
backToHome: 'Volver al inicio',
spaceAccountCannotChangePassword:
'Las cuentas de Space no pueden cambiar la contraseña aquí',
'Las cuentas de LangBot no pueden cambiar la contraseña aquí',
theme: 'Tema',
changePassword: 'Cambiar contraseña',
currentPassword: 'Contraseña actual',
@@ -261,9 +261,10 @@ const esES = {
llmModels: 'Modelos LLM',
localProvider: 'Local',
localProviderDescription: 'Modelos configurados y gestionados localmente',
spaceProviderDescription: 'Modelos sincronizados desde tu cuenta de Space',
spaceProviderDescription:
'Modelos sincronizados desde tu cuenta de LangBot',
spaceDisabledForLocalAccount:
'Inicia sesión con Space para usar modelos en la nube',
'Inicia sesión con una cuenta de LangBot para usar modelos en la nube',
syncModels: 'Sincronizar',
syncSuccess:
'Sincronización completa: {{created}} creados, {{updated}} actualizados',
@@ -302,11 +303,12 @@ const esES = {
langbotModelsDescription: 'Modelos en la nube impulsados por LangBot Space',
credits: 'Créditos',
loginWithSpace: 'Iniciar sesión con una cuenta de LangBot',
loginToUseModels: 'Inicia sesión con Space para usar modelos en la nube',
loginToUseModels:
'Inicia sesión con una cuenta de LangBot para usar modelos en la nube',
noModels: 'No hay modelos configurados',
langbotModels: 'Modelos LangBot',
spaceTrialTooltip:
'¡Créditos de prueba gratuitos disponibles! Inicia sesión con Space para acceder a modelos en la nube sin configuración.',
'¡Créditos de prueba gratuitos disponibles! Inicia sesión con una cuenta de LangBot para acceder a modelos en la nube sin configuración.',
unlockModels: 'Inicia sesión para usar',
editProvider: 'Editar proveedor',
addProvider: 'Añadir proveedor',
@@ -341,9 +343,9 @@ const esES = {
},
ownerMustBindSpace:
'The Workspace owner must connect Space for LangBot Models.',
'The Workspace owner must connect a LangBot Account for LangBot Models.',
usesOwnerSpaceBilling:
"Uses the Workspace owner's Space billing and credits.",
"Uses the Workspace owner's LangBot Account billing and credits.",
},
bots: {
title: 'Bots',
@@ -1251,13 +1253,13 @@ const esES = {
adminAccountNote:
'La cuenta que uses aquí se establecerá como cuenta de administrador',
register: 'Registrarse',
initWithSpace: 'Inicializar con Space',
initWithSpace: 'Inicializar con una cuenta de LangBot',
spaceRecommended:
'Recomendado: Usa API de modelos oficiales estables y servicios en la nube',
spaceInfoTip1:
'Space proporciona servicios de autenticación unificada de cuentas sin subir ninguna de tu información sensible.',
spaceInfoTip2:
'Iniciar sesión con una cuenta de Space te da acceso a los modelos de LangBot y otros servicios en la nube, incluyendo créditos gratuitos de llamadas a modelos para ayudarte a comenzar rápidamente.',
'Iniciar sesión con una cuenta de LangBot te da acceso a los modelos de LangBot y otros servicios en la nube, incluyendo créditos gratuitos de llamadas a modelos para ayudarte a comenzar rápidamente.',
spaceInfoTip3:
'Tu método de inicio de sesión no afecta otras funciones. Puedes configurar y usar modelos de otras fuentes en cualquier momento.',
registerLocal: 'Registrar cuenta local',
@@ -1315,35 +1317,35 @@ const esES = {
passwordNotSet: 'No establecida',
passwordSetDescription:
'La contraseña está establecida, puedes iniciar sesión con correo y contraseña',
spaceStatus: 'Cuenta de Space',
spaceStatus: 'Cuenta de LangBot',
spaceBound: 'Vinculada',
spaceNotBound: 'No vinculada',
spaceBoundDescription:
'Cuenta de Space vinculada, API de modelos oficiales y servicios en la nube disponibles',
bindSpace: 'Vincular cuenta de Space',
'Cuenta de LangBot vinculada, API de modelos oficiales y servicios en la nube disponibles',
bindSpace: 'Vincular cuenta de LangBot',
bindSpaceDescription:
'Vincular para usar API de modelos oficiales y servicios en la nube',
bindSpaceButton: 'Vincular',
bindSpaceConfirmTitle: 'Confirmar vinculación',
bindSpaceConfirmDescription:
'Estás a punto de vincular tu instancia local a una cuenta de Space',
'Estás a punto de vincular tu instancia local a una cuenta de LangBot',
bindSpaceWarning:
'Después de vincular, tu correo de inicio de sesión se cambiará de {{localEmail}} al correo de la cuenta de Space.',
bindSpaceSuccess: 'Cuenta de Space vinculada correctamente',
bindSpaceFailed: 'Error al vincular la cuenta de Space',
'Después de vincular, tu correo de inicio de sesión se cambiará de {{localEmail}} al correo de la cuenta de LangBot.',
bindSpaceSuccess: 'Cuenta de LangBot vinculada correctamente',
bindSpaceFailed: 'Error al vincular la cuenta de LangBot',
bindSpaceInvalidState:
'Solicitud de vinculación no válida. Por favor, inténtalo de nuevo desde la configuración de la cuenta.',
setPasswordHint:
'Establece una contraseña para iniciar sesión con correo y contraseña',
spaceEmailMismatch:
'El correo de inicio de sesión de Space no coincide con el correo de la cuenta local',
'El correo de la cuenta de LangBot no coincide con el correo de la cuenta local',
space_account_not_registeredTitle: 'Account not registered',
space_account_not_registered:
'No local account is registered for this Space email. Ask the Workspace owner for an invitation.',
space_account_binding_requiredTitle: 'Space connection required',
'No local account is registered for this LangBot Account email. Ask the Workspace owner for an invitation.',
space_account_binding_requiredTitle: 'LangBot Account connection required',
space_account_binding_required:
'This local account must connect Space from Account settings before using Space login.',
'This local account must connect a LangBot Account from Account settings before using LangBot Account login.',
},
monitoring: {
title: 'Panel de control',
+24 -23
View File
@@ -86,19 +86,19 @@ const jaJP = {
'おすすめ:公式の安定したモデル API とクラウドサービスを利用',
loginLocal: 'ローカルアカウントでログイン',
loginWithPassword: 'パスワードでログイン',
spaceLoginTitle: 'Space でログイン',
spaceLoginTitle: 'LangBot アカウントでログイン',
spaceLoginDescription:
'QRコードをスキャンするか、下のリンクにアクセスして認証してください',
spaceLoginUserCode: '認証コード',
spaceLoginExpires: 'コードは {{seconds}} 秒後に期限切れになります',
spaceLoginWaiting: '認証を待っています...',
spaceLoginSuccess: '認証に成功しました',
spaceLoginFailed: 'Space ログインに失敗しました',
spaceLoginFailed: 'LangBot アカウントログインに失敗しました',
spaceLoginExpired:
'認証コードの有効期限が切れました。もう一度お試しください',
spaceLoginCancel: 'キャンセル',
spaceLoginVisitLink: 'リンクにアクセス',
spaceLoginProcessing: 'Space でログイン中',
spaceLoginProcessing: 'LangBot アカウントでログイン中',
spaceLoginProcessingDescription:
'ログインを完了しています。しばらくお待ちください...',
spaceLoginSuccessDescription: 'LangBot にリダイレクト中...',
@@ -107,7 +107,7 @@ const jaJP = {
backToLogin: 'ログインに戻る',
backToHome: 'ホームに戻る',
spaceAccountCannotChangePassword:
'Space アカウントはここでパスワードを変更できません',
'LangBot アカウントはここでパスワードを変更できません',
theme: 'テーマ',
changePassword: 'パスワードを変更',
currentPassword: '現在のパスワード',
@@ -257,8 +257,9 @@ const jaJP = {
llmModels: 'LLM モデル',
localProvider: 'ローカル',
localProviderDescription: 'ローカルで設定・管理されているモデル',
spaceProviderDescription: 'Space アカウントから同期されたモデル',
spaceDisabledForLocalAccount: 'Space でログインしてクラウドモデルを使用',
spaceProviderDescription: 'LangBot アカウントから同期されたモデル',
spaceDisabledForLocalAccount:
'LangBot アカウントでログインしてクラウドモデルを使用',
syncModels: '同期',
syncSuccess: '同期完了:{{created}} 件作成、{{updated}} 件更新',
syncError: '同期に失敗しました:',
@@ -296,15 +297,15 @@ const jaJP = {
langbotModelsDescription: 'LangBot Space が提供するクラウドモデル',
credits: 'クレジット',
loginWithSpace: 'LangBot アカウントでログイン',
loginToUseModels: 'Space でログインしてクラウドモデルを使用',
loginToUseModels: 'LangBot アカウントでログインしてクラウドモデルを使用',
ownerMustBindSpace:
'LangBot モデルを使うにはワークスペース所有者が Space を連携する必要があります。',
'LangBot モデルを使うにはワークスペース所有者が LangBot アカウントを連携する必要があります。',
usesOwnerSpaceBilling:
'ワークスペース所有者の Space 課金とクレジットを使用します。',
'ワークスペース所有者の LangBot アカウント課金とクレジットを使用します。',
noModels: 'モデルがありません',
langbotModels: 'LangBot モデル',
spaceTrialTooltip:
'無料トライアルクレジットが利用可能!Space でログインして、設定不要でクラウドモデルを使用できます。',
'無料トライアルクレジットが利用可能!LangBot アカウントでログインして、設定不要でクラウドモデルを使用できます。',
unlockModels: 'ログインして使用',
editProvider: 'プロバイダーを編集',
addProvider: 'プロバイダーを追加',
@@ -1223,13 +1224,13 @@ const jaJP = {
adminAccountNote:
'ここで初期化されたアカウントは管理者アカウントとして使用されます',
register: '登録',
initWithSpace: 'Space で初期化',
initWithSpace: 'LangBot アカウントで初期化',
spaceRecommended:
'おすすめ:公式の安定したモデル API とクラウドサービスを利用',
spaceInfoTip1:
'Space は統一されたアカウント認証サービスを提供し、機密情報をアップロードすることはありません。',
spaceInfoTip2:
'Space アカウントでログインすると、LangBot Models などのクラウドサービスを利用でき、無料のモデル呼び出しクレジットで迅速に開始できます。',
'LangBot アカウントでログインすると、LangBot Models などのクラウドサービスを利用でき、無料のモデル呼び出しクレジットで迅速に開始できます。',
spaceInfoTip3:
'ログイン方法は他の機能に影響しません。いつでも他のソースからモデルを設定して使用できます。',
registerLocal: 'ローカルアカウントを登録',
@@ -1286,33 +1287,33 @@ const jaJP = {
passwordNotSet: '未設定',
passwordSetDescription:
'パスワードが設定されています。メールとパスワードでログインできます',
spaceStatus: 'Space アカウント',
spaceStatus: 'LangBot アカウント',
spaceBound: '連携済み',
spaceNotBound: '未連携',
spaceBoundDescription:
'Space アカウントと連携済み、公式モデル API とクラウドサービスが利用可能',
bindSpace: 'Space アカウントを連携',
'LangBot アカウントと連携済み、公式モデル API とクラウドサービスが利用可能',
bindSpace: 'LangBot アカウントを連携',
bindSpaceDescription: '連携して公式モデル API とクラウドサービスを利用',
bindSpaceButton: '連携',
bindSpaceConfirmTitle: '連携を確認',
bindSpaceConfirmDescription:
'ローカルインスタンスを Space アカウントに連携しようとしています',
'ローカルインスタンスを LangBot アカウントに連携しようとしています',
bindSpaceWarning:
'連携後、ログインメールアドレスは {{localEmail}} から Space アカウントのメールアドレスに変更されます。',
bindSpaceSuccess: 'Space アカウントの連携に成功しました',
bindSpaceFailed: 'Space アカウントの連携に失敗しました',
'連携後、ログインメールアドレスは {{localEmail}} から LangBot アカウントのメールアドレスに変更されます。',
bindSpaceSuccess: 'LangBot アカウントの連携に成功しました',
bindSpaceFailed: 'LangBot アカウントの連携に失敗しました',
bindSpaceInvalidState:
'無効な連携リクエストです。アカウント設定から再度お試しください。',
setPasswordHint:
'パスワードを設定するとメールとパスワードでログインできます',
spaceEmailMismatch:
'Spaceログインのメールアドレスがローカルアカウントのメールアドレスと一致しません',
'LangBot アカウントのメールアドレスがローカルアカウントのメールアドレスと一致しません',
space_account_not_registeredTitle: 'アカウントが登録されていません',
space_account_not_registered:
'この Space メールアドレスのローカルアカウントはありません。ワークスペース所有者に招待を依頼してください。',
space_account_binding_requiredTitle: 'Space の連携が必要です',
'この LangBot アカウントのメールアドレスのローカルアカウントはありません。ワークスペース所有者に招待を依頼してください。',
space_account_binding_requiredTitle: 'LangBot アカウントの連携が必要です',
space_account_binding_required:
'Space ログインを使用する前に、アカウント設定でこのローカルアカウントを Space に連携してください。',
'LangBot アカウントログインを使用する前に、アカウント設定でこのローカルアカウントを LangBot アカウントに連携してください。',
},
workspace: {
title: 'ワークスペース',
+24 -23
View File
@@ -85,18 +85,18 @@ const ruRU = {
'Рекомендуется: Используйте официальные стабильные API моделей и облачные сервисы',
loginLocal: 'Войти с локальной учётной записью',
loginWithPassword: 'Войти с паролем',
spaceLoginTitle: 'Войти через Space',
spaceLoginTitle: 'Войти с аккаунтом LangBot',
spaceLoginDescription:
'Отсканируйте QR-код или перейдите по ссылке ниже для авторизации',
spaceLoginUserCode: 'Ваш код',
spaceLoginExpires: 'Код истекает через {{seconds}} секунд',
spaceLoginWaiting: 'Ожидание авторизации...',
spaceLoginSuccess: 'Авторизация успешна',
spaceLoginFailed: 'Ошибка входа через Space',
spaceLoginFailed: 'Ошибка входа с аккаунтом LangBot',
spaceLoginExpired: 'Код авторизации истёк, попробуйте снова',
spaceLoginCancel: 'Отмена',
spaceLoginVisitLink: 'Перейти по ссылке',
spaceLoginProcessing: 'Вход через Space',
spaceLoginProcessing: 'Вход с аккаунтом LangBot',
spaceLoginProcessingDescription:
'Пожалуйста, подождите, пока мы завершим вход...',
spaceLoginSuccessDescription: 'Перенаправление в LangBot...',
@@ -105,7 +105,7 @@ const ruRU = {
backToLogin: 'Вернуться к входу',
backToHome: 'На главную',
spaceAccountCannotChangePassword:
'Для аккаунтов Space невозможно изменить пароль здесь',
'Для аккаунтов LangBot невозможно изменить пароль здесь',
theme: 'Тема',
changePassword: 'Изменить пароль',
currentPassword: 'Текущий пароль',
@@ -259,9 +259,9 @@ const ruRU = {
localProvider: 'Локальный',
localProviderDescription: 'Модели, настроенные и управляемые локально',
spaceProviderDescription:
'Модели, синхронизированные из вашего аккаунта Space',
'Модели, синхронизированные из вашего аккаунта LangBot',
spaceDisabledForLocalAccount:
'Войдите через Space, чтобы использовать облачные модели',
'Войдите с аккаунтом LangBot, чтобы использовать облачные модели',
syncModels: 'Синхронизировать',
syncSuccess:
'Синхронизация завершена: {{created}} создано, {{updated}} обновлено',
@@ -300,11 +300,12 @@ const ruRU = {
langbotModelsDescription: 'Облачные модели на базе LangBot Space',
credits: 'Кредиты',
loginWithSpace: 'Войти с аккаунтом LangBot',
loginToUseModels: 'Войдите через Space, чтобы использовать облачные модели',
loginToUseModels:
'Войдите с аккаунтом LangBot, чтобы использовать облачные модели',
noModels: 'Модели не настроены',
langbotModels: 'Модели LangBot',
spaceTrialTooltip:
'Доступны бесплатные пробные кредиты! Войдите через Space, чтобы получить доступ к облачным моделям без настройки.',
'Доступны бесплатные пробные кредиты! Войдите с аккаунтом LangBot, чтобы получить доступ к облачным моделям без настройки.',
unlockModels: 'Войдите для использования',
editProvider: 'Редактировать провайдера',
addProvider: 'Добавить провайдера',
@@ -340,9 +341,9 @@ const ruRU = {
},
ownerMustBindSpace:
'The Workspace owner must connect Space for LangBot Models.',
'The Workspace owner must connect a LangBot Account for LangBot Models.',
usesOwnerSpaceBilling:
"Uses the Workspace owner's Space billing and credits.",
"Uses the Workspace owner's LangBot Account billing and credits.",
},
bots: {
title: 'Боты',
@@ -1229,13 +1230,13 @@ const ruRU = {
adminAccountNote:
'Указанная учётная запись будет настроена как администратор',
register: 'Регистрация',
initWithSpace: 'Инициализация через Space',
initWithSpace: 'Инициализация с аккаунтом LangBot',
spaceRecommended:
'Рекомендуется: Используйте официальные стабильные API моделей и облачные сервисы',
spaceInfoTip1:
'Space предоставляет единую службу аутентификации без загрузки конфиденциальной информации.',
spaceInfoTip2:
'Вход через Space даёт доступ к моделям LangBot и облачным сервисам, включая бесплатные кредиты для быстрого старта.',
'Вход с аккаунтом LangBot даёт доступ к моделям LangBot и облачным сервисам, включая бесплатные кредиты для быстрого старта.',
spaceInfoTip3:
'Способ входа не влияет на другие функции. Вы можете настроить модели из других источников в любое время.',
registerLocal: 'Зарегистрировать локальную учётную запись',
@@ -1291,34 +1292,34 @@ const ruRU = {
passwordNotSet: 'Не установлен',
passwordSetDescription:
'Пароль установлен, вы можете входить с email и паролем',
spaceStatus: 'Аккаунт Space',
spaceStatus: 'Аккаунт LangBot',
spaceBound: 'Привязан',
spaceNotBound: 'Не привязан',
spaceBoundDescription:
'Аккаунт Space привязан, доступны официальные API моделей и облачные сервисы',
bindSpace: 'Привязать аккаунт Space',
'Аккаунт LangBot привязан, доступны официальные API моделей и облачные сервисы',
bindSpace: 'Привязать аккаунт LangBot',
bindSpaceDescription:
'Привяжите для использования официальных API моделей и облачных сервисов',
bindSpaceButton: 'Привязать',
bindSpaceConfirmTitle: 'Подтверждение привязки',
bindSpaceConfirmDescription:
'Вы собираетесь привязать локальный экземпляр к аккаунту Space',
'Вы собираетесь привязать локальный экземпляр к аккаунту LangBot',
bindSpaceWarning:
'После привязки ваш email для входа будет изменён с {{localEmail}} на email аккаунта Space.',
bindSpaceSuccess: 'Аккаунт Space успешно привязан',
bindSpaceFailed: 'Не удалось привязать аккаунт Space',
'После привязки ваш email для входа будет изменён с {{localEmail}} на email аккаунта LangBot.',
bindSpaceSuccess: 'Аккаунт LangBot успешно привязан',
bindSpaceFailed: 'Не удалось привязать аккаунт LangBot',
bindSpaceInvalidState:
'Недействительный запрос привязки. Повторите попытку из настроек аккаунта.',
setPasswordHint: 'Установите пароль для входа с email и паролем',
spaceEmailMismatch:
'Email входа через Space не совпадает с email локальной учётной записи',
'Email входа с аккаунтом LangBot не совпадает с email локальной учётной записи',
space_account_not_registeredTitle: 'Account not registered',
space_account_not_registered:
'No local account is registered for this Space email. Ask the Workspace owner for an invitation.',
space_account_binding_requiredTitle: 'Space connection required',
'No local account is registered for this LangBot Account email. Ask the Workspace owner for an invitation.',
space_account_binding_requiredTitle: 'LangBot Account connection required',
space_account_binding_required:
'This local account must connect Space from Account settings before using Space login.',
'This local account must connect a LangBot Account from Account settings before using LangBot Account login.',
},
monitoring: {
title: 'Мониторинг',
+26 -23
View File
@@ -85,18 +85,18 @@ const thTH = {
'แนะนำ: ใช้ API โมเดลที่เสถียรอย่างเป็นทางการและบริการคลาวด์',
loginLocal: 'เข้าสู่ระบบด้วยบัญชีท้องถิ่น',
loginWithPassword: 'เข้าสู่ระบบด้วยรหัสผ่าน',
spaceLoginTitle: 'เข้าสู่ระบบด้วย Space',
spaceLoginTitle: 'เข้าสู่ระบบด้วยบัญชี LangBot',
spaceLoginDescription:
'สแกน QR code หรือเข้าชมลิงก์ด้านล่างเพื่อยืนยันสิทธิ์',
spaceLoginUserCode: 'รหัสของคุณ',
spaceLoginExpires: 'รหัสจะหมดอายุใน {{seconds}} วินาที',
spaceLoginWaiting: 'กำลังรอการยืนยันสิทธิ์...',
spaceLoginSuccess: 'ยืนยันสิทธิ์สำเร็จ',
spaceLoginFailed: 'เข้าสู่ระบบ Space ล้มเหลว',
spaceLoginFailed: 'เข้าสู่ระบบด้วยบัญชี LangBot ล้มเหลว',
spaceLoginExpired: 'รหัสยืนยันหมดอายุแล้ว กรุณาลองใหม่',
spaceLoginCancel: 'ยกเลิก',
spaceLoginVisitLink: 'เข้าชมลิงก์',
spaceLoginProcessing: 'กำลังเข้าสู่ระบบด้วย Space',
spaceLoginProcessing: 'กำลังเข้าสู่ระบบด้วยบัญชี LangBot',
spaceLoginProcessingDescription: 'กรุณารอสักครู่ขณะดำเนินการเข้าสู่ระบบ...',
spaceLoginSuccessDescription: 'กำลังเปลี่ยนเส้นทางไปยัง LangBot...',
spaceLoginError: 'เข้าสู่ระบบล้มเหลว',
@@ -104,7 +104,7 @@ const thTH = {
backToLogin: 'กลับไปหน้าเข้าสู่ระบบ',
backToHome: 'กลับไปหน้าแรก',
spaceAccountCannotChangePassword:
'บัญชี Space ไม่สามารถเปลี่ยนรหัสผ่านได้ที่นี่',
'บัญชี LangBot ไม่สามารถเปลี่ยนรหัสผ่านได้ที่นี่',
theme: 'ธีม',
changePassword: 'เปลี่ยนรหัสผ่าน',
currentPassword: 'รหัสผ่านปัจจุบัน',
@@ -252,8 +252,9 @@ const thTH = {
llmModels: 'โมเดล LLM',
localProvider: 'ท้องถิ่น',
localProviderDescription: 'โมเดลที่กำหนดค่าและจัดการในเครื่อง',
spaceProviderDescription: 'โมเดลที่ซิงค์จากบัญชี Space ของคุณ',
spaceDisabledForLocalAccount: 'เข้าสู่ระบบด้วย Space เพื่อใช้โมเดลคลาวด์',
spaceProviderDescription: 'โมเดลที่ซิงค์จากบัญชี LangBot ของคุณ',
spaceDisabledForLocalAccount:
'เข้าสู่ระบบด้วยบัญชี LangBot เพื่อใช้โมเดลคลาวด์',
syncModels: 'ซิงค์',
syncSuccess:
'ซิงค์เสร็จสมบูรณ์: สร้าง {{created}} รายการ, อัปเดต {{updated}} รายการ',
@@ -289,11 +290,11 @@ const thTH = {
langbotModelsDescription: 'โมเดลคลาวด์ขับเคลื่อนโดย LangBot Space',
credits: 'เครดิต',
loginWithSpace: 'เข้าสู่ระบบด้วยบัญชี LangBot',
loginToUseModels: 'เข้าสู่ระบบด้วย Space เพื่อใช้โมเดลคลาวด์',
loginToUseModels: 'เข้าสู่ระบบด้วยบัญชี LangBot เพื่อใช้โมเดลคลาวด์',
noModels: 'ยังไม่มีโมเดลที่กำหนดค่า',
langbotModels: 'โมเดล LangBot',
spaceTrialTooltip:
'มีเครดิตทดลองใช้งานฟรี! เข้าสู่ระบบด้วย Space เพื่อเข้าถึงโมเดลคลาวด์โดยไม่ต้องตั้งค่า',
'มีเครดิตทดลองใช้งานฟรี! เข้าสู่ระบบด้วยบัญชี LangBot เพื่อเข้าถึงโมเดลคลาวด์โดยไม่ต้องตั้งค่า',
unlockModels: 'เข้าสู่ระบบเพื่อใช้งาน',
editProvider: 'แก้ไขผู้ให้บริการ',
addProvider: 'เพิ่มผู้ให้บริการ',
@@ -327,9 +328,9 @@ const thTH = {
},
ownerMustBindSpace:
'The Workspace owner must connect Space for LangBot Models.',
'The Workspace owner must connect a LangBot Account for LangBot Models.',
usesOwnerSpaceBilling:
"Uses the Workspace owner's Space billing and credits.",
"Uses the Workspace owner's LangBot Account billing and credits.",
},
bots: {
title: 'บอท',
@@ -1202,13 +1203,13 @@ const thTH = {
description: 'นี่เป็นครั้งแรกที่คุณเริ่มใช้งาน LangBot',
adminAccountNote: 'บัญชีที่คุณใช้ที่นี่จะถูกตั้งเป็นบัญชีผู้ดูแลระบบ',
register: 'ลงทะเบียน',
initWithSpace: 'เริ่มต้นด้วย Space',
initWithSpace: 'เริ่มต้นด้วยบัญชี LangBot',
spaceRecommended:
'แนะนำ: ใช้ API โมเดลที่เสถียรอย่างเป็นทางการและบริการคลาวด์',
spaceInfoTip1:
'Space ให้บริการยืนยันตัวตนแบบรวมโดยไม่อัปโหลดข้อมูลสำคัญใดๆ ของคุณ',
spaceInfoTip2:
'การเข้าสู่ระบบด้วยบัญชี Space ช่วยให้คุณเข้าถึงโมเดล LangBot และบริการคลาวด์อื่นๆ รวมถึงเครดิตเรียกใช้โมเดลฟรีเพื่อช่วยให้คุณเริ่มต้นได้อย่างรวดเร็ว',
'การเข้าสู่ระบบด้วยบัญชี LangBot ช่วยให้คุณเข้าถึงโมเดล LangBot และบริการคลาวด์อื่นๆ รวมถึงเครดิตเรียกใช้โมเดลฟรีเพื่อช่วยให้คุณเริ่มต้นได้อย่างรวดเร็ว',
spaceInfoTip3:
'วิธีการเข้าสู่ระบบของคุณไม่มีผลต่อฟีเจอร์อื่นๆ คุณสามารถกำหนดค่าและใช้โมเดลจากแหล่งอื่นได้ตลอดเวลา',
registerLocal: 'ลงทะเบียนบัญชีท้องถิ่น',
@@ -1263,30 +1264,32 @@ const thTH = {
passwordNotSet: 'ยังไม่ได้ตั้งค่า',
passwordSetDescription:
'ตั้งรหัสผ่านแล้ว คุณสามารถเข้าสู่ระบบด้วยอีเมลและรหัสผ่าน',
spaceStatus: 'บัญชี Space',
spaceStatus: 'บัญชี LangBot',
spaceBound: 'ผูกแล้ว',
spaceNotBound: 'ยังไม่ผูก',
spaceBoundDescription:
'ผูกบัญชี Space แล้ว สามารถใช้ API โมเดลอย่างเป็นทางการและบริการคลาวด์ได้',
bindSpace: 'ผูกบัญชี Space',
'ผูกบัญชี LangBot แล้ว สามารถใช้ API โมเดลอย่างเป็นทางการและบริการคลาวด์ได้',
bindSpace: 'ผูกบัญชี LangBot',
bindSpaceDescription: 'ผูกเพื่อใช้ API โมเดลอย่างเป็นทางการและบริการคลาวด์',
bindSpaceButton: 'ผูก',
bindSpaceConfirmTitle: 'ยืนยันการผูก',
bindSpaceConfirmDescription: 'คุณกำลังจะผูกอินสแตนซ์ท้องถิ่นกับบัญชี Space',
bindSpaceConfirmDescription:
'คุณกำลังจะผูกอินสแตนซ์ท้องถิ่นกับบัญชี LangBot',
bindSpaceWarning:
'หลังจากผูกแล้ว อีเมลเข้าสู่ระบบของคุณจะเปลี่ยนจาก {{localEmail}} เป็นอีเมลบัญชี Space',
bindSpaceSuccess: 'ผูกบัญชี Space สำเร็จ',
bindSpaceFailed: 'ผูกบัญชี Space ล้มเหลว',
'หลังจากผูกแล้ว อีเมลเข้าสู่ระบบของคุณจะเปลี่ยนจาก {{localEmail}} เป็นอีเมลบัญชี LangBot',
bindSpaceSuccess: 'ผูกบัญชี LangBot สำเร็จ',
bindSpaceFailed: 'ผูกบัญชี LangBot ล้มเหลว',
bindSpaceInvalidState: 'คำขอผูกไม่ถูกต้อง กรุณาลองใหม่จากการตั้งค่าบัญชี',
setPasswordHint: 'ตั้งรหัสผ่านเพื่อเข้าสู่ระบบด้วยอีเมลและรหัสผ่าน',
spaceEmailMismatch: 'อีเมลเข้าสู่ระบบ Space ไม่ตรงกับอีเมลบัญชีท้องถิ่น',
spaceEmailMismatch:
'อีเมลเข้าสู่ระบบด้วยบัญชี LangBot ไม่ตรงกับอีเมลบัญชีท้องถิ่น',
space_account_not_registeredTitle: 'Account not registered',
space_account_not_registered:
'No local account is registered for this Space email. Ask the Workspace owner for an invitation.',
space_account_binding_requiredTitle: 'Space connection required',
'No local account is registered for this LangBot Account email. Ask the Workspace owner for an invitation.',
space_account_binding_requiredTitle: 'LangBot Account connection required',
space_account_binding_required:
'This local account must connect Space from Account settings before using Space login.',
'This local account must connect a LangBot Account from Account settings before using LangBot Account login.',
},
monitoring: {
title: 'แดชบอร์ด',
+24 -23
View File
@@ -86,18 +86,18 @@ const viVN = {
'Khuyến nghị: Sử dụng API mô hình ổn định chính thức và dịch vụ đám mây',
loginLocal: 'Đăng nhập với tài khoản cục bộ',
loginWithPassword: 'Đăng nhập bằng mật khẩu',
spaceLoginTitle: 'Đăng nhập với Space',
spaceLoginTitle: 'Đăng nhập bằng tài khoản LangBot',
spaceLoginDescription:
'Quét mã QR hoặc truy cập liên kết bên dưới để ủy quyền',
spaceLoginUserCode: 'Mã của bạn',
spaceLoginExpires: 'Mã hết hạn sau {{seconds}} giây',
spaceLoginWaiting: 'Đang chờ ủy quyền...',
spaceLoginSuccess: 'Ủy quyền thành công',
spaceLoginFailed: 'Đăng nhập Space thất bại',
spaceLoginFailed: 'Đăng nhập bằng tài khoản LangBot thất bại',
spaceLoginExpired: 'Mã ủy quyền đã hết hạn, vui lòng thử lại',
spaceLoginCancel: 'Hủy',
spaceLoginVisitLink: 'Truy cập liên kết',
spaceLoginProcessing: 'Đang đăng nhập với Space',
spaceLoginProcessing: 'Đang đăng nhập bằng tài khoản LangBot',
spaceLoginProcessingDescription:
'Vui lòng chờ trong khi chúng tôi hoàn tất đăng nhập...',
spaceLoginSuccessDescription: 'Đang chuyển hướng đến LangBot...',
@@ -106,7 +106,7 @@ const viVN = {
backToLogin: 'Quay lại đăng nhập',
backToHome: 'Quay lại trang chủ',
spaceAccountCannotChangePassword:
'Tài khoản Space không thể đổi mật khẩu tại đây',
'Tài khoản LangBot không thể đổi mật khẩu tại đây',
theme: 'Giao diện',
changePassword: 'Đổi mật khẩu',
currentPassword: 'Mật khẩu hiện tại',
@@ -258,9 +258,9 @@ const viVN = {
localProvider: 'Cục bộ',
localProviderDescription: 'Các mô hình được cấu hình và quản lý cục bộ',
spaceProviderDescription:
'Các mô hình được đồng bộ từ tài khoản Space của bạn',
'Các mô hình được đồng bộ từ tài khoản LangBot của bạn',
spaceDisabledForLocalAccount:
'Đăng nhập với Space để sử dụng mô hình đám mây',
'Đăng nhập bằng tài khoản LangBot để sử dụng mô hình đám mây',
syncModels: 'Đồng bộ',
syncSuccess:
'Đồng bộ hoàn tất: {{created}} đã tạo, {{updated}} đã cập nhật',
@@ -297,11 +297,12 @@ const viVN = {
langbotModelsDescription: 'Mô hình đám mây được cung cấp bởi LangBot Space',
credits: 'Tín dụng',
loginWithSpace: 'Đăng nhập bằng tài khoản LangBot',
loginToUseModels: 'Đăng nhập với Space để sử dụng mô hình đám mây',
loginToUseModels:
'Đăng nhập bằng tài khoản LangBot để sử dụng mô hình đám mây',
noModels: 'Chưa cấu hình mô hình nào',
langbotModels: 'Mô hình LangBot',
spaceTrialTooltip:
'Có tín dụng dùng thử miễn phí! Đăng nhập với Space để truy cập mô hình đám mây không cần cấu hình.',
'Có tín dụng dùng thử miễn phí! Đăng nhập bằng tài khoản LangBot để truy cập mô hình đám mây không cần cấu hình.',
unlockModels: 'Đăng nhập để sử dụng',
editProvider: 'Chỉnh sửa nhà cung cấp',
addProvider: 'Thêm nhà cung cấp',
@@ -336,9 +337,9 @@ const viVN = {
},
ownerMustBindSpace:
'The Workspace owner must connect Space for LangBot Models.',
'The Workspace owner must connect a LangBot Account for LangBot Models.',
usesOwnerSpaceBilling:
"Uses the Workspace owner's Space billing and credits.",
"Uses the Workspace owner's LangBot Account billing and credits.",
},
bots: {
title: 'Bot',
@@ -1222,13 +1223,13 @@ const viVN = {
adminAccountNote:
'Tài khoản bạn sử dụng ở đây sẽ được đặt làm tài khoản quản trị viên',
register: 'Đăng ký',
initWithSpace: 'Khởi tạo với Space',
initWithSpace: 'Khởi tạo bằng tài khoản LangBot',
spaceRecommended:
'Khuyến nghị: Sử dụng API mô hình ổn định chính thức và dịch vụ đám mây',
spaceInfoTip1:
'Space cung cấp dịch vụ xác thực tài khoản thống nhất mà không tải lên bất kỳ thông tin nhạy cảm nào của bạn.',
spaceInfoTip2:
'Đăng nhập bằng tài khoản Space cho phép bạn truy cập Mô hình LangBot và các dịch vụ đám mây khác, bao gồm tín dụng gọi mô hình miễn phí để giúp bạn bắt đầu nhanh chóng.',
'Đăng nhập bằng tài khoản LangBot cho phép bạn truy cập Mô hình LangBot và các dịch vụ đám mây khác, bao gồm tín dụng gọi mô hình miễn phí để giúp bạn bắt đầu nhanh chóng.',
spaceInfoTip3:
'Phương thức đăng nhập của bạn không ảnh hưởng đến các tính năng khác. Bạn có thể cấu hình và sử dụng mô hình từ các nguồn khác bất cứ lúc nào.',
registerLocal: 'Đăng ký tài khoản cục bộ',
@@ -1285,34 +1286,34 @@ const viVN = {
passwordNotSet: 'Chưa đặt',
passwordSetDescription:
'Mật khẩu đã được đặt, bạn có thể đăng nhập bằng email và mật khẩu',
spaceStatus: 'Tài khoản Space',
spaceStatus: 'Tài khoản LangBot',
spaceBound: 'Đã liên kết',
spaceNotBound: 'Chưa liên kết',
spaceBoundDescription:
'Tài khoản Space đã liên kết, có thể sử dụng API mô hình chính thức và dịch vụ đám mây',
bindSpace: 'Liên kết tài khoản Space',
'Tài khoản LangBot đã liên kết, có thể sử dụng API mô hình chính thức và dịch vụ đám mây',
bindSpace: 'Liên kết tài khoản LangBot',
bindSpaceDescription:
'Liên kết để sử dụng API mô hình chính thức và dịch vụ đám mây',
bindSpaceButton: 'Liên kết',
bindSpaceConfirmTitle: 'Xác nhận liên kết',
bindSpaceConfirmDescription:
'Bạn sắp liên kết phiên bản cục bộ với tài khoản Space',
'Bạn sắp liên kết phiên bản cục bộ với tài khoản LangBot',
bindSpaceWarning:
'Sau khi liên kết, email đăng nhập của bạn sẽ được đổi từ {{localEmail}} sang email tài khoản Space.',
bindSpaceSuccess: 'Liên kết tài khoản Space thành công',
bindSpaceFailed: 'Liên kết tài khoản Space thất bại',
'Sau khi liên kết, email đăng nhập của bạn sẽ được đổi từ {{localEmail}} sang email tài khoản LangBot.',
bindSpaceSuccess: 'Liên kết tài khoản LangBot thành công',
bindSpaceFailed: 'Liên kết tài khoản LangBot thất bại',
bindSpaceInvalidState:
'Yêu cầu liên kết không hợp lệ. Vui lòng thử lại từ cài đặt tài khoản.',
setPasswordHint: 'Đặt mật khẩu để đăng nhập bằng email và mật khẩu',
spaceEmailMismatch:
'Email đăng nhập Space không khớp với email tài khoản cục bộ',
'Email tài khoản LangBot không khớp với email tài khoản cục bộ',
space_account_not_registeredTitle: 'Account not registered',
space_account_not_registered:
'No local account is registered for this Space email. Ask the Workspace owner for an invitation.',
space_account_binding_requiredTitle: 'Space connection required',
'No local account is registered for this LangBot Account email. Ask the Workspace owner for an invitation.',
space_account_binding_requiredTitle: 'LangBot Account connection required',
space_account_binding_required:
'This local account must connect Space from Account settings before using Space login.',
'This local account must connect a LangBot Account from Account settings before using LangBot Account login.',
},
monitoring: {
title: 'Bảng điều khiển',
+24 -23
View File
@@ -83,24 +83,24 @@ const zhHans = {
spaceLoginRecommended: '推荐:使用官方提供的稳定模型 API 和云服务',
loginLocal: '使用本地账号登录',
loginWithPassword: '通过密码登录',
spaceLoginTitle: '通过 Space 登录',
spaceLoginTitle: '通过 LangBot 账号登录',
spaceLoginDescription: '扫描二维码或访问下方链接进行授权',
spaceLoginUserCode: '您的验证码',
spaceLoginExpires: '验证码将在 {{seconds}} 秒后过期',
spaceLoginWaiting: '等待授权中...',
spaceLoginSuccess: '授权成功',
spaceLoginFailed: 'Space 登录失败',
spaceLoginFailed: 'LangBot 账号登录失败',
spaceLoginExpired: '验证码已过期,请重试',
spaceLoginCancel: '取消',
spaceLoginVisitLink: '访问链接',
spaceLoginProcessing: '正在通过 Space 登录',
spaceLoginProcessing: '正在通过 LangBot 账号登录',
spaceLoginProcessingDescription: '请稍候,正在完成登录...',
spaceLoginSuccessDescription: '正在跳转到 LangBot...',
spaceLoginError: '登录失败',
spaceLoginNoCode: '缺少授权码',
backToLogin: '返回登录',
backToHome: '返回首页',
spaceAccountCannotChangePassword: 'Space无法在此修改密码',
spaceAccountCannotChangePassword: 'LangBot无法在此修改密码',
theme: '主题',
changePassword: '修改密码',
currentPassword: '当前密码',
@@ -243,8 +243,8 @@ const zhHans = {
llmModels: '对话模型',
localProvider: '本地',
localProviderDescription: '在本地配置和管理的模型',
spaceProviderDescription: '从您的 Space同步的模型',
spaceDisabledForLocalAccount: '使用 Space 登录以使用云端模型',
spaceProviderDescription: '从您的 LangBot同步的模型',
spaceDisabledForLocalAccount: '使用 LangBot 账号登录以使用云端模型',
syncModels: '同步',
syncSuccess: '同步完成:创建 {{created}} 个,更新 {{updated}} 个',
syncError: '同步失败:',
@@ -279,13 +279,14 @@ const zhHans = {
langbotModelsDescription: 'LangBot Space 提供的云端模型',
credits: '积分',
loginWithSpace: '使用 LangBot 账号登录',
loginToUseModels: '通过 Space 登录以使用云端模型',
ownerMustBindSpace: '工作区所有者需要绑定 Space 才能使用 LangBot 模型。',
usesOwnerSpaceBilling: '使用工作区所有者的 Space 计费与积分。',
loginToUseModels: '通过 LangBot 账号登录以使用云端模型',
ownerMustBindSpace:
'工作区所有者需要绑定 LangBot 账号才能使用 LangBot 模型。',
usesOwnerSpaceBilling: '使用工作区所有者的 LangBot 账号计费与积分。',
noModels: '暂无模型',
langbotModels: 'LangBot 模型',
spaceTrialTooltip:
'免费试用积分已就绪!通过 Space 登录即可零配置使用云端模型。',
'免费试用积分已就绪!通过 LangBot 账号登录即可零配置使用云端模型。',
unlockModels: '登录以使用',
editProvider: '编辑供应商',
addProvider: '添加供应商',
@@ -1161,11 +1162,11 @@ const zhHans = {
description: '这是您首次启动 LangBot',
adminAccountNote: '您在此处初始化使用的账号将作为管理员账号',
register: '注册',
initWithSpace: '通过 Space 初始化',
initWithSpace: '通过 LangBot 账号初始化',
spaceRecommended: '推荐:使用官方提供的稳定模型 API 和云服务',
spaceInfoTip1: 'Space 提供统一的账户鉴权服务,不会上传您的任何敏感信息。',
spaceInfoTip2:
'使用 Space登录可使用 LangBot Models 等云服务,您将会获得一定的免费模型调用额度帮助您快速起步。',
'使用 LangBot登录可使用 LangBot Models 等云服务,您将会获得一定的免费模型调用额度帮助您快速起步。',
spaceInfoTip3:
'登录方式不会影响其他功能,您在任何情况下都可以配置使用其他来源的模型。',
registerLocal: '注册本地账号',
@@ -1219,28 +1220,28 @@ const zhHans = {
passwordSet: '已设置',
passwordNotSet: '未设置',
passwordSetDescription: '您已设置本地密码,可使用邮箱密码登录',
spaceStatus: 'Space',
spaceStatus: 'LangBot',
spaceBound: '已绑定',
spaceNotBound: '未绑定',
spaceBoundDescription: '已绑定 Space,可使用官方模型 API 和云服务',
bindSpace: '绑定 Space',
spaceBoundDescription: '已绑定 LangBot,可使用官方模型 API 和云服务',
bindSpace: '绑定 LangBot',
bindSpaceDescription: '绑定后可使用官方模型 API 和云服务',
bindSpaceButton: '绑定',
bindSpaceConfirmTitle: '确认绑定',
bindSpaceConfirmDescription: '您即将把本地实例绑定到 Space',
bindSpaceConfirmDescription: '您即将把本地实例绑定到 LangBot',
bindSpaceWarning:
'绑定后,您的登录邮箱将从 {{localEmail}} 更改为 Space的邮箱。',
bindSpaceSuccess: 'Space绑定成功',
bindSpaceFailed: '绑定 Space失败',
'绑定后,您的登录邮箱将从 {{localEmail}} 更改为 LangBot的邮箱。',
bindSpaceSuccess: 'LangBot绑定成功',
bindSpaceFailed: '绑定 LangBot失败',
bindSpaceInvalidState: '无效的绑定请求,请从账户设置重新发起',
setPasswordHint: '设置密码后可使用邮箱密码登录',
spaceEmailMismatch: 'Space登录账号邮箱与本实例账号邮箱不匹配',
spaceEmailMismatch: 'LangBot 账号邮箱与本实例账号邮箱不匹配',
space_account_not_registeredTitle: '账户尚未注册',
space_account_not_registered:
'此 Space 邮箱尚无本地账户,请联系工作区所有者获取邀请。',
space_account_binding_requiredTitle: '需要绑定 Space',
'此 LangBot 账号邮箱尚无本地账户,请联系工作区所有者获取邀请。',
space_account_binding_requiredTitle: '需要绑定 LangBot 账号',
space_account_binding_required:
'此本地账户必须先在账户设置中绑定 Space,才能使用 Space 登录。',
'此本地账户必须先在账户设置中绑定 LangBot 账号,才能使用 LangBot 账号登录。',
},
workspace: {
title: '工作区',
+23 -23
View File
@@ -83,24 +83,24 @@ const zhHant = {
spaceLoginRecommended: '推薦:使用官方提供的穩定模型 API 和雲服務',
loginLocal: '使用本地帳號登入',
loginWithPassword: '透過密碼登入',
spaceLoginTitle: '透過 Space 登入',
spaceLoginTitle: '透過 LangBot 帳號登入',
spaceLoginDescription: '掃描二維碼或訪問下方連結進行授權',
spaceLoginUserCode: '您的驗證碼',
spaceLoginExpires: '驗證碼將在 {{seconds}} 秒後過期',
spaceLoginWaiting: '等待授權中...',
spaceLoginSuccess: '授權成功',
spaceLoginFailed: 'Space 登入失敗',
spaceLoginFailed: 'LangBot 帳號登入失敗',
spaceLoginExpired: '驗證碼已過期,請重試',
spaceLoginCancel: '取消',
spaceLoginVisitLink: '訪問連結',
spaceLoginProcessing: '正在透過 Space 登入',
spaceLoginProcessing: '正在透過 LangBot 帳號登入',
spaceLoginProcessingDescription: '請稍候,正在完成登入...',
spaceLoginSuccessDescription: '正在跳轉到 LangBot...',
spaceLoginError: '登入失敗',
spaceLoginNoCode: '缺少授權碼',
backToLogin: '返回登入',
backToHome: '返回首頁',
spaceAccountCannotChangePassword: 'Space無法在此修改密碼',
spaceAccountCannotChangePassword: 'LangBot無法在此修改密碼',
theme: '主題',
changePassword: '修改密碼',
currentPassword: '當前密碼',
@@ -244,8 +244,8 @@ const zhHant = {
llmModels: '對話模型',
localProvider: '本地',
localProviderDescription: '在本地設定和管理的模型',
spaceProviderDescription: '從您的 Space同步的模型',
spaceDisabledForLocalAccount: '使用 Space 登入以使用雲端模型',
spaceProviderDescription: '從您的 LangBot同步的模型',
spaceDisabledForLocalAccount: '使用 LangBot 帳號登入以使用雲端模型',
syncModels: '同步',
syncSuccess: '同步完成:建立 {{created}} 個,更新 {{updated}} 個',
syncError: '同步失敗:',
@@ -279,11 +279,11 @@ const zhHant = {
langbotModelsDescription: '由 LangBot Space 提供的雲端模型',
credits: '積分',
loginWithSpace: '使用 LangBot 帳號登入',
loginToUseModels: '使用 Space 登入以使用雲端模型',
loginToUseModels: '使用 LangBot 帳號登入以使用雲端模型',
noModels: '暫無模型',
langbotModels: 'LangBot 模型',
spaceTrialTooltip:
'免費試用積分已就緒!使用 Space 登入即可零設定使用雲端模型。',
'免費試用積分已就緒!使用 LangBot 帳號登入即可零設定使用雲端模型。',
unlockModels: '登入以使用',
editProvider: '編輯供應商',
addProvider: '新增供應商',
@@ -317,9 +317,9 @@ const zhHant = {
},
ownerMustBindSpace:
'The Workspace owner must connect Space for LangBot Models.',
'The Workspace owner must connect a LangBot Account for LangBot Models.',
usesOwnerSpaceBilling:
"Uses the Workspace owner's Space billing and credits.",
"Uses the Workspace owner's LangBot Account billing and credits.",
},
bots: {
title: '機器人',
@@ -1163,11 +1163,11 @@ const zhHant = {
description: '這是您首次啟動 LangBot',
adminAccountNote: '您在此處初始化使用的帳號將作為管理員帳號',
register: '註冊',
initWithSpace: '透過 Space 初始化',
initWithSpace: '透過 LangBot 帳號初始化',
spaceRecommended: '推薦:使用官方提供的穩定模型 API 和雲服務',
spaceInfoTip1: 'Space 提供統一的帳戶鑑權服務,不會上傳您的任何敏感資訊。',
spaceInfoTip2:
'使用 Space登入可使用 LangBot Models 等雲服務,您將會獲得一定的免費模型調用額度幫助您快速起步。',
'使用 LangBot登入可使用 LangBot Models 等雲服務,您將會獲得一定的免費模型調用額度幫助您快速起步。',
spaceInfoTip3:
'登入方式不會影響其他功能,您在任何情況下都可以配置使用其他來源的模型。',
registerLocal: '註冊本地帳號',
@@ -1221,29 +1221,29 @@ const zhHant = {
passwordSet: '已設定',
passwordNotSet: '未設定',
passwordSetDescription: '您已設定本地密碼,可使用電子郵件密碼登入',
spaceStatus: 'Space',
spaceStatus: 'LangBot',
spaceBound: '已綁定',
spaceNotBound: '未綁定',
spaceBoundDescription: '已綁定 Space,可使用官方模型 API 和雲服務',
bindSpace: '綁定 Space',
spaceBoundDescription: '已綁定 LangBot,可使用官方模型 API 和雲服務',
bindSpace: '綁定 LangBot',
bindSpaceDescription: '綁定後可使用官方模型 API 和雲服務',
bindSpaceButton: '綁定',
bindSpaceConfirmTitle: '確認綁定',
bindSpaceConfirmDescription: '您即將把本地實例綁定到 Space',
bindSpaceConfirmDescription: '您即將把本地實例綁定到 LangBot',
bindSpaceWarning:
'綁定後,您的登入電子郵件將從 {{localEmail}} 更改為 Space的電子郵件。',
bindSpaceSuccess: 'Space綁定成功',
bindSpaceFailed: '綁定 Space失敗',
'綁定後,您的登入電子郵件將從 {{localEmail}} 更改為 LangBot的電子郵件。',
bindSpaceSuccess: 'LangBot綁定成功',
bindSpaceFailed: '綁定 LangBot失敗',
bindSpaceInvalidState: '無效的綁定請求,請從帳戶設定重新發起',
setPasswordHint: '設定密碼後可使用電子郵件密碼登入',
spaceEmailMismatch: 'Space登入帳號電子郵件與本實例帳號電子郵件不匹配',
spaceEmailMismatch: 'LangBot 帳號電子郵件與本實例帳號電子郵件不匹配',
space_account_not_registeredTitle: 'Account not registered',
space_account_not_registered:
'No local account is registered for this Space email. Ask the Workspace owner for an invitation.',
space_account_binding_requiredTitle: 'Space connection required',
'No local account is registered for this LangBot Account email. Ask the Workspace owner for an invitation.',
space_account_binding_requiredTitle: 'LangBot Account connection required',
space_account_binding_required:
'This local account must connect Space from Account settings before using Space login.',
'This local account must connect a LangBot Account from Account settings before using LangBot Account login.',
},
monitoring: {
title: '儀表盤',
@@ -0,0 +1,47 @@
import assert from 'node:assert/strict';
import { readdirSync, readFileSync } from 'node:fs';
import test from 'node:test';
const localeDir = new URL('../../src/i18n/locales/', import.meta.url);
const localeFiles = readdirSync(localeDir).filter((name) =>
name.endsWith('.ts'),
);
const deprecatedAccountCopy = [
/Initialize with Space/i,
/Login with Space/i,
/Logging in with Space/i,
/Space login/i,
/Space accounts?/i,
/Bind Space Account/i,
/Authorize with Space/i,
/通过 Space 登录/,
/使用 Space 登录/,
/Space 登录/,
/Space 账户/,
/Space 帳戶/,
/绑定 Space/,
/綁定 Space/,
/Space アカウント/,
/Space でログイン/,
/cuenta de Space/i,
/cuentas de Space/i,
/cuenta Space/i,
/tài khoản Space/i,
/บัญชี Space/,
/аккаунт(?:ов|а)? Space/i,
/аккаунт Space/i,
];
test('user-facing account authentication copy uses LangBot Account terminology', () => {
const violations = [];
for (const file of localeFiles) {
const source = readFileSync(new URL(file, localeDir), 'utf8');
for (const pattern of deprecatedAccountCopy) {
if (pattern.test(source)) violations.push(`${file}: ${pattern}`);
}
}
assert.deepEqual(violations, []);
});