Files
SnapOtter/apps/docs/ru/guide/translations.md
T
SnapOtterandGitHub 4963ab3bbd feat(docs-i18n): translate all documentation into 20 languages
All 181 docs markdown files translated into 20 languages (apps/docs/<locale>/**). Companion to the i18n code PR; admin-merged because the file count exceeds GitHub's per-PR CI trigger limit. Validated by pnpm i18n:check (all surfaces, 0 stale/missing) and a clean all-locale docs build.
2026-07-11 13:52:47 +08:00

15 KiB
Raw Blame History

description, i18n_source_hash, i18n_provenance, i18n_output_hash
description i18n_source_hash i18n_provenance i18n_output_hash
21 поддерживаемый язык и способы создания или улучшения переводов для SnapOtter с помощью системы i18n, контролируемой TypeScript. 55837d9fdaef human f94f8a0a6f70

Руководство по переводам

SnapOtter поставляется с 21 языком из коробки. Система i18n использует лёгкое собственное среда выполнения с полнотой локалей, контролируемой TypeScript, и динамическим разбиением кода.

Поддерживаемые языки

Code Language Native Name Direction
en Английский English LTR
zh-CN Китайский (упрощённый) 简体中文 LTR
zh-TW Китайский (традиционный) 繁體中文 LTR
ja Японский 日本語 LTR
ko Корейский 한국어 LTR
es Испанский Español LTR
fr Французский Français LTR
it Итальянский Italiano LTR
pt-BR Португальский (Бразилия) Português (Brasil) LTR
de Немецкий Deutsch LTR
nl Нидерландский Nederlands LTR
sv Шведский Svenska LTR
ru Русский Русский LTR
pl Польский Polski LTR
uk Украинский Українська LTR
ar Арабский العربية RTL
tr Турецкий Türkçe LTR
hi Хинди हिन्दी LTR
vi Вьетнамский Tiếng Việt LTR
id Индонезийский Bahasa Indonesia LTR
th Тайский ไทย LTR

Как работает определение языка

SnapOtter использует трёхуровневый порядок разрешения:

  1. Предпочтение пользователя — хранится в localStorage("snapotter-locale") и синхронизируется с настройками пользователя при авторизации
  2. Автоопределение браузера — проходит по массиву navigator.languages с сопоставлением префиксов BCP 47
  3. Умолчание экземпляра — переменная окружения DEFAULT_LOCALE администратора (запрашивается из GET /api/v1/config/locale)
  4. Запасной вариант — английский — всегда доступен

Пользователи могут менять язык из:

  • Селектора-глобуса в подвале (десктоп, всегда виден)
  • Селектора языка на странице входа (до авторизации)
  • Раздела Настройки > Общие (предпочтение конкретного пользователя)
  • Выпадающего списка языков в мобильной боковой панели
  • Раздел Настройки > Система задаёт умолчание для всего экземпляра (только администратор)

Как работают переводы

Все строки интерфейса находятся в packages/shared/src/i18n/. Эталонный файл — en.ts, который экспортирует типизированный объект со всеми строками, используемыми приложением (~1500 ключей). Другие языки — это отдельные файлы (например, de.ts, fr.ts), которые экспортируют ту же структуру.

Тип TranslationKeys использует DeepStringRecord, чтобы принимать любое строковое значение, при этом требуя соблюдения структуры ключей. TypeScript обнаруживает отсутствующие ключи в любом файле перевода во время компиляции.

Во время выполнения загружается только активная локаль через динамический import(), что сохраняет основной бандл небольшим.

Использование переводов в компонентах

import { useTranslation } from "@/contexts/i18n-context";
import { format, plural } from "@/lib/format";

function MyComponent() {
  const { t, locale, setLocale } = useTranslation();
  
  return (
    <div>
      <h1>{t.common.settings}</h1>
      <p>{format(t.settings.people.deleteConfirm, { username: "admin" })}</p>
      <p>{plural(count, t.automate.fileCount, t.automate.fileCountPlural)}</p>
    </div>
  );
}

Как внести перевод

Мы приветствуем PR с переводами напрямую. Вы можете улучшить существующую локаль или добавить новую.

Чтобы сообщить об ошибке перевода, не отправляя код, откройте GitHub Issue с указанием языка, неверной строки и предлагаемого исправления.

::: tip PR с переводами не требуют предварительного одобрения. Форкните репозиторий, внесите изменения и откройте PR. См. Руководство для контрибьюторов, где описан полный процесс PR и требование CLA. :::

Как создать или обновить перевод

1. Форк и клонирование

git clone https://github.com/<your-username>/snapotter.git
cd snapotter
pnpm install

2. Скопируйте эталонный файл (только для нового языка)

Пропустите этот шаг, если вы улучшаете существующий перевод.

cp packages/shared/src/i18n/en.ts packages/shared/src/i18n/XX.ts

3. Переведите строки

Откройте свой новый файл и переведите каждое строковое значение. Сохраняйте структуру объекта и ключи в точности такими же.

import type { TranslationKeys } from "./en.js";

export const xx: TranslationKeys = {
  common: {
    upload: "Your translation here",
    // ... translate all entries
  },
  // ... translate all sections
} as const;

Правила:

  • Не переводите ключи объекта, только строковые значения
  • Сохраняйте as const в конце
  • Импортируйте TranslationKeys из ./en.js и типизируйте свой экспорт
  • Сохраняйте плейсхолдеры {variable} в точности как есть
  • Массивы (rotatingPhrases, progressMessages) должны иметь одинаковое количество элементов
  • Не переводите: SnapOtter, JPEG, PNG, WebP, EXIF, API и другие технические термины

4. Зарегистрируйте локаль (только для нового языка)

Добавьте свою локаль в SUPPORTED_LOCALES в packages/shared/src/i18n/index.ts:

{ code: "xx", name: "Language Name", nativeName: "Native Name", dir: "ltr" },

5. Проверьте

pnpm typecheck    # catches missing or mistyped keys
pnpm lint         # formatting check
pnpm dev          # manually verify strings appear correctly

6. Отправьте

Откройте PR против main с заголовком вида feat(i18n): add Swedish translation или fix(i18n): correct German typos. Бот CLA попросит вас подписать соглашение при первом вкладе.

Добавление новых ключей перевода

При добавлении новой функции, которой нужны новые строки интерфейса:

  1. Сначала добавьте новые ключи в en.ts (эталонный файл)
  2. Запустите pnpm typecheck — каждый файл локали упадёт, если в нём нет нового ключа
  3. Добавьте новый ключ во все файлы локалей (используйте английский как временный запасной вариант)

Конфигурация

Задайте язык экземпляра по умолчанию через переменную окружения:

DEFAULT_LOCALE: "de"  # German as the default for all new users

Справочник по файлам

File Purpose
packages/shared/src/i18n/en.ts Английские строки (эталонная локаль, ~1500 ключей)
packages/shared/src/i18n/index.ts SUPPORTED_LOCALES, loadTranslations(), экспорт типов
packages/shared/src/i18n/<locale>.ts Файлы перевода по языкам
apps/web/src/contexts/i18n-context.tsx I18nProvider, хук useTranslation()
apps/web/src/lib/format.ts Хелперы format(), plural(), formatFileSize()
apps/api/src/routes/config.ts Публичная конечная точка GET /api/v1/config/locale

Перевод веб-сайта, документации и справочника по API

Поддержка 21 языка выше относится к приложению. Публичный веб-сайт (snapotter.com), этот сайт документации и справочник по REST API также переведены на все 21 язык отдельным пайплайном с хеш-контролем, который повторно использует те же названия и описания инструментов из packages/shared/src/i18n, чтобы терминология оставалась согласованной везде.

Машинный перевод по умолчанию

Каждая неанглийская страница на веб-сайте и в документации переводится машинно при первом проходе (сессией Claude Code, а не сторонним сервисом) и несёт небольшой закрываемый баннер, сообщающий об этом, со ссылкой обратно сюда. Это сделано намеренно: так все 21 язык выходят быстро и честно, а затем сообществу предлагается доработать наиболее важные страницы. Машинный перевод передаёт смысл; проверка человеком делает текст естественным.

Как пайплайн решает, что переводить

Каждая переводимая единица английского источника хешируется, и хеш хранится рядом с её переводом. При каждом запуске пайплайн:

  • переводит любую единицу, у которой ещё нет перевода,
  • пропускает любую единицу, чей сохранённый хеш всё ещё совпадает с английским источником,
  • заново переводит машинную единицу, когда её английский источник меняется,
  • и помечает доработанную человеком единицу как stale (требует проверки), когда её английский источник меняется, вместо того чтобы перезаписывать вашу работу.

Доработка веб-перевода через PR

Вы улучшаете перевод веб-сайта, документации или справочника по API так же, как вы улучшаете локаль приложения: редактируя сгенерированный файл и открывая PR.

  1. Найдите сгенерированный перевод для вашего языка:
    • строки интерфейса веб-сайта: apps/landing/src/i18n/<locale>.json
    • страница документации: apps/docs/<locale>/**.md
    • справочник по API: apps/api/src/openapi.<locale>.yaml
  2. Отредактируйте текст. Сохраняйте код, ссылки, {placeholders} и любые маркеры ⸤I18N…⸥ в точности как есть; валидатор пайплайна отклоняет перевод, который отбрасывает или переупорядочивает их.
  3. Откройте PR. Редактирование единицы переключает её происхождение с machine на human, так что пайплайн никогда не перезапишет её при последующем запуске. Если английский источник позже изменится, ваша единица будет помечена stale для проверки, а не молча заменена.

Чтобы сообщить об ошибке перевода, не отправляя код, откройте GitHub Issue с указанием URL страницы, языка, неверного текста и вашего предлагаемого исправления.

::: tip Пайплайн перевода запускают мейнтейнеры; вам не нужен ключ API, чтобы внести вклад. Просто отредактируйте сгенерированный файл и откройте PR. См. scripts/i18n/README.md, где описано, как работает пайплайн. :::