|
|
@@ -0,0 +1,681 @@
|
|
|
+# Компонент LanguageSwitcher - Полная документация
|
|
|
+
|
|
|
+## Назначение компонента
|
|
|
+
|
|
|
+`LanguageSwitcher` - компонент для переключения языков интерфейса в мультиязычном приложении. Интегрируется с глобальной системой мультиязычности, обеспечивает удобный интерфейс выбора языка и сохраняет предпочтения пользователя.
|
|
|
+
|
|
|
+## Импорт и регистрация
|
|
|
+
|
|
|
+```coffee
|
|
|
+# В основном файле приложения (app/temp.coffee)
|
|
|
+components:
|
|
|
+ 'language-switcher': require 'app/shared/LanguageSwitcher'
|
|
|
+```
|
|
|
+
|
|
|
+## Базовое использование
|
|
|
+
|
|
|
+```pug
|
|
|
+//- Минимальное использование
|
|
|
+language-switcher
|
|
|
+
|
|
|
+//- В навигационной панели
|
|
|
+div(class="flex items-center space-x-4")
|
|
|
+ language-switcher
|
|
|
+ themetoggle
|
|
|
+```
|
|
|
+
|
|
|
+## Полный список props
|
|
|
+
|
|
|
+### `size` (опциональный)
|
|
|
+- **Тип:** `String`
|
|
|
+- **По умолчанию:** `'md'`
|
|
|
+- **Допустимые значения:** `'sm'`, `'md'`, `'lg'`
|
|
|
+- **Описание:** Размер переключателя
|
|
|
+- **Пример:**
|
|
|
+ ```pug
|
|
|
+ language-switcher(size="sm")
|
|
|
+ language-switcher(size="lg")
|
|
|
+ ```
|
|
|
+
|
|
|
+### `variant` (опциональный)
|
|
|
+- **Тип:** `String`
|
|
|
+- **По умолчанию:** `'dropdown'`
|
|
|
+- **Допустимые значения:** `'dropdown'`, `'buttons'`, `'select'`, `'flags'`
|
|
|
+- **Описание:** Вариант отображения переключателя
|
|
|
+- **Пример:**
|
|
|
+ ```pug
|
|
|
+ language-switcher(variant="buttons")
|
|
|
+ language-switcher(variant="flags")
|
|
|
+ ```
|
|
|
+
|
|
|
+### `showNativeNames` (опциональный)
|
|
|
+- **Тип:** `Boolean`
|
|
|
+- **По умолчанию:** `true`
|
|
|
+- **Описание:** Показывать названия на родном языке
|
|
|
+- **Пример:**
|
|
|
+ ```pug
|
|
|
+ language-switcher(:showNativeNames="false")
|
|
|
+ ```
|
|
|
+
|
|
|
+### `showFlags` (опциональный)
|
|
|
+- **Тип:** `Boolean`
|
|
|
+- **По умолчанию:** `true`
|
|
|
+- **Описание:** Показывать флаги (для соответствующих вариантов)
|
|
|
+- **Пример:**
|
|
|
+ ```pug
|
|
|
+ language-switcher(:showFlags="false")
|
|
|
+ ```
|
|
|
+
|
|
|
+### `position` (опциональный)
|
|
|
+- **Тип:** `String`
|
|
|
+- **По умолчанию:** `'bottom-start'`
|
|
|
+- **Допустимые значения:** `'top'`, `'top-start'`, `'top-end'`, `'bottom'`, `'bottom-start'`, `'bottom-end'`, `'left'`, `'right'`
|
|
|
+- **Описание:** Позиция выпадающего списка
|
|
|
+- **Пример:**
|
|
|
+ ```pug
|
|
|
+ language-switcher(position="bottom-end")
|
|
|
+ ```
|
|
|
+
|
|
|
+### `languages` (опциональный)
|
|
|
+- **Тип:** `Array`
|
|
|
+- **По умолчанию:** `[{ code: 'ru', name: 'Russian', native: 'Русский', flag: '🇷🇺' }, { code: 'en', name: 'English', native: 'English', flag: '🇺🇸' }, { code: 'tj', name: 'Tajik', native: 'Тоҷикӣ', flag: '🇹🇯' }]`
|
|
|
+- **Описание:** Список доступных языков
|
|
|
+- **Пример:**
|
|
|
+ ```pug
|
|
|
+ language-switcher(:languages="customLanguages")
|
|
|
+ ```
|
|
|
+
|
|
|
+### `storageKey` (опциональный)
|
|
|
+- **Тип:** `String`
|
|
|
+- **По умолчанию:** `'borbad-language'`
|
|
|
+- **Описание:** Ключ для сохранения в localStorage
|
|
|
+- **Пример:**
|
|
|
+ ```pug
|
|
|
+ language-switcher(storageKey="my-app-language")
|
|
|
+ ```
|
|
|
+
|
|
|
+### `autoClose` (опциональный)
|
|
|
+- **Тип:** `Boolean`
|
|
|
+- **По умолчанию:** `true`
|
|
|
+- **Описание:** Автоматически закрывать после выбора
|
|
|
+- **Пример:**
|
|
|
+ ```pug
|
|
|
+ language-switcher(:autoClose="false")
|
|
|
+ ```
|
|
|
+
|
|
|
+### `class` (опциональный)
|
|
|
+- **Тип:** `String | Object | Array`
|
|
|
+- **По умолчанию:** `''`
|
|
|
+- **Описание:** Дополнительные CSS классы
|
|
|
+- **Пример:**
|
|
|
+ ```pug
|
|
|
+ language-switcher(class="border border-gray-300 rounded-lg")
|
|
|
+ ```
|
|
|
+
|
|
|
+## События (Events)
|
|
|
+
|
|
|
+### `@change`
|
|
|
+- **Описание:** Событие смены языка
|
|
|
+- **Payload:** `{ language: String, previousLanguage: String }`
|
|
|
+- **Пример:**
|
|
|
+ ```pug
|
|
|
+ language-switcher(@change="handleLanguageChange")
|
|
|
+ ```
|
|
|
+
|
|
|
+### `@open`
|
|
|
+- **Описание:** Событие открытия переключателя
|
|
|
+- **Payload:** `None`
|
|
|
+- **Пример:**
|
|
|
+ ```pug
|
|
|
+ language-switcher(@open="handleLanguageSwitcherOpen")
|
|
|
+ ```
|
|
|
+
|
|
|
+### `@close`
|
|
|
+- **Описание:** Событие закрытия переключателя
|
|
|
+- **Payload:** `None`
|
|
|
+- **Пример:**
|
|
|
+ ```pug
|
|
|
+ language-switcher(@close="handleLanguageSwitcherClose")
|
|
|
+ ```
|
|
|
+
|
|
|
+## Слоты (Slots)
|
|
|
+
|
|
|
+### `[button-content]`
|
|
|
+- **Описание:** Кастомное содержимое кнопки переключателя
|
|
|
+- **Пример:**
|
|
|
+ ```pug
|
|
|
+ language-switcher
|
|
|
+ template([button-content])
|
|
|
+ div(class="flex items-center space-x-2")
|
|
|
+ icon(name="globe")
|
|
|
+ span Язык
|
|
|
+ ```
|
|
|
+
|
|
|
+### `[language-option]`
|
|
|
+- **Описание:** Кастомное отображение опции языка
|
|
|
+- **Scope:** `{ language: Object, isActive: Boolean }`
|
|
|
+- **Пример:**
|
|
|
+ ```pug
|
|
|
+ language-switcher
|
|
|
+ template([language-option]="{ language, isActive }")
|
|
|
+ div(class="flex items-center space-x-3 p-2")
|
|
|
+ span(class="text-lg") {{ language.flag }}
|
|
|
+ div(class="flex flex-col")
|
|
|
+ span(class="font-medium") {{ language.native }}
|
|
|
+ span(class="text-sm text-gray-500") {{ language.name }}
|
|
|
+ span(
|
|
|
+ v-if="isActive"
|
|
|
+ class="text-green-500 ml-auto"
|
|
|
+ ) ✓
|
|
|
+ ```
|
|
|
+
|
|
|
+### `[before-options]`
|
|
|
+- **Описание:** Контент перед списком языков
|
|
|
+- **Пример:**
|
|
|
+ ```pug
|
|
|
+ language-switcher
|
|
|
+ template([before-options])
|
|
|
+ div(class="p-3 border-b border-gray-200 dark:border-gray-700")
|
|
|
+ h3(class="font-semibold") Выберите язык
|
|
|
+ ```
|
|
|
+
|
|
|
+### `[after-options]`
|
|
|
+- **Описание:** Контент после списка языков
|
|
|
+- **Пример:**
|
|
|
+ ```pug
|
|
|
+ language-switcher
|
|
|
+ template([after-options])
|
|
|
+ div(class="p-3 border-t border-gray-200 dark:border-gray-700")
|
|
|
+ p(class="text-sm text-gray-500") Помогите с переводом
|
|
|
+ ```
|
|
|
+
|
|
|
+## Поддерживаемые языки по умолчанию
|
|
|
+
|
|
|
+### Русский (`ru`)
|
|
|
+- **Название:** Russian
|
|
|
+- **Родное название:** Русский
|
|
|
+- **Флаг:** 🇷🇺
|
|
|
+
|
|
|
+### Английский (`en`)
|
|
|
+- **Название:** English
|
|
|
+- **Родное название:** English
|
|
|
+- **Флаг:** 🇺🇸
|
|
|
+
|
|
|
+### Таджикский (`tj`)
|
|
|
+- **Название:** Tajik
|
|
|
+- **Родное название:** Тоҷикӣ
|
|
|
+- **Флаг:** 🇹🇯
|
|
|
+
|
|
|
+## Примеры использования
|
|
|
+
|
|
|
+### 1. Базовые варианты отображения
|
|
|
+```pug
|
|
|
+//- Выпадающий список (по умолчанию)
|
|
|
+language-switcher
|
|
|
+
|
|
|
+//- Кнопки
|
|
|
+language-switcher(variant="buttons")
|
|
|
+
|
|
|
+//- Select элемент
|
|
|
+language-switcher(variant="select")
|
|
|
+
|
|
|
+//- Флаги
|
|
|
+language-switcher(variant="flags")
|
|
|
+
|
|
|
+//- Разные размеры
|
|
|
+div(class="flex space-x-2 items-center")
|
|
|
+ language-switcher(size="sm")
|
|
|
+ language-switcher(size="md")
|
|
|
+ language-switcher(size="lg")
|
|
|
+```
|
|
|
+
|
|
|
+### 2. Кастомные языки
|
|
|
+```pug
|
|
|
+language-switcher(
|
|
|
+ :languages="[
|
|
|
+ { code: 'ru', name: 'Russian', native: 'Русский', flag: '🇷🇺' },
|
|
|
+ { code: 'en', name: 'English', native: 'English', flag: '🇺🇸' },
|
|
|
+ { code: 'de', name: 'German', native: 'Deutsch', flag: '🇩🇪' },
|
|
|
+ { code: 'fr', name: 'French', native: 'Français', flag: '🇫🇷' }
|
|
|
+ ]"
|
|
|
+)
|
|
|
+```
|
|
|
+
|
|
|
+### 3. Интеграция с навигацией
|
|
|
+```pug
|
|
|
+header(class="bg-white dark:bg-gray-800 shadow-sm")
|
|
|
+ div(class="container mx-auto px-4")
|
|
|
+ div(class="flex justify-between items-center py-4")
|
|
|
+ //- Логотип
|
|
|
+ app-link(to="/" class="text-xl font-bold") Борбад
|
|
|
+
|
|
|
+ //- Навигация с переключателями
|
|
|
+ div(class="flex items-center space-x-4")
|
|
|
+ nav(class="flex space-x-6")
|
|
|
+ app-link(to="/events") Мероприятия
|
|
|
+ app-link(to="/blog") Блог
|
|
|
+
|
|
|
+ //- Переключатели
|
|
|
+ language-switcher(
|
|
|
+ variant="flags"
|
|
|
+ size="sm"
|
|
|
+ :showNativeNames="false"
|
|
|
+ )
|
|
|
+ themetoggle(variant="icon-only")
|
|
|
+```
|
|
|
+
|
|
|
+### 4. В мобильном меню
|
|
|
+```pug
|
|
|
+div(class="mobile-menu bg-white dark:bg-gray-800 p-6")
|
|
|
+ div(class="space-y-4")
|
|
|
+ app-link(to="/" class="block py-2") Главная
|
|
|
+ app-link(to="/events" class="block py-2") Мероприятия
|
|
|
+
|
|
|
+ //- Переключатель языка
|
|
|
+ div(class="pt-4 border-t dark:border-gray-700")
|
|
|
+ language-switcher(
|
|
|
+ variant="buttons"
|
|
|
+ class="w-full"
|
|
|
+ )
|
|
|
+```
|
|
|
+
|
|
|
+### 5. С кастомными слотами
|
|
|
+```pug
|
|
|
+language-switcher
|
|
|
+ template([button-content])
|
|
|
+ div(class="flex items-center space-x-2")
|
|
|
+ icon(name="translate" class="w-4 h-4")
|
|
|
+ span {{ _.currentLanguage.toUpperCase() }}
|
|
|
+
|
|
|
+ template([before-options])
|
|
|
+ div(class="p-3 bg-blue-50 dark:bg-blue-900")
|
|
|
+ p(class="text-sm text-blue-700 dark:text-blue-300") Выберите язык интерфейса
|
|
|
+
|
|
|
+ template([language-option]="{ language, isActive }")
|
|
|
+ div(
|
|
|
+ :class="[
|
|
|
+ 'flex items-center space-x-3 p-3 rounded-lg transition-colors',
|
|
|
+ isActive ? 'bg-blue-100 dark:bg-blue-800' : 'hover:bg-gray-100 dark:hover:bg-gray-700'
|
|
|
+ ]"
|
|
|
+ )
|
|
|
+ span(class="text-xl") {{ language.flag }}
|
|
|
+ div(class="flex-1")
|
|
|
+ div(class="font-medium") {{ language.native }}
|
|
|
+ div(class="text-sm text-gray-500 dark:text-gray-400") {{ language.name }}
|
|
|
+ icon(
|
|
|
+ v-if="isActive"
|
|
|
+ name="check"
|
|
|
+ class="w-4 h-4 text-blue-600 dark:text-blue-400"
|
|
|
+ )
|
|
|
+```
|
|
|
+
|
|
|
+### 6. С обработкой событий
|
|
|
+```pug
|
|
|
+language-switcher(
|
|
|
+ @change="onLanguageChange"
|
|
|
+ @open="onLanguageSwitcherOpen"
|
|
|
+ @close="onLanguageSwitcherClose"
|
|
|
+)
|
|
|
+
|
|
|
+//- В methods компонента
|
|
|
+methods:
|
|
|
+ onLanguageChange: ({ language, previousLanguage }) ->
|
|
|
+ debug.log "Язык изменен: "+previousLanguage+" -> "+language
|
|
|
+
|
|
|
+ # Аналитика
|
|
|
+ analytics.track('language_changed', {
|
|
|
+ new_language: language,
|
|
|
+ previous_language: previousLanguage
|
|
|
+ })
|
|
|
+
|
|
|
+ # Обновление мета-тегов
|
|
|
+ @updateHtmlLang(language)
|
|
|
+
|
|
|
+ onLanguageSwitcherOpen: ->
|
|
|
+ debug.log "Переключатель языка открыт"
|
|
|
+ analytics.track('language_switcher_opened')
|
|
|
+
|
|
|
+ onLanguageSwitcherClose: ->
|
|
|
+ debug.log "Переключатель языка закрыт"
|
|
|
+```
|
|
|
+
|
|
|
+## Программное взаимодействие
|
|
|
+
|
|
|
+### Получение текущего языка
|
|
|
+```coffee
|
|
|
+# Через глобальный объект
|
|
|
+currentLanguage = _.currentLanguage
|
|
|
+
|
|
|
+# Через AppDB
|
|
|
+currentLanguage = AppDB.multilingual.currentLanguage
|
|
|
+
|
|
|
+# Через EventBus
|
|
|
+EventBus.on 'language_changed', (language) ->
|
|
|
+ debug.log "Текущий язык: "+language
|
|
|
+```
|
|
|
+
|
|
|
+### Установка языка программно
|
|
|
+```coffee
|
|
|
+# Через глобальный объект
|
|
|
+_.changeLanguage('en')
|
|
|
+
|
|
|
+# Через AppDB
|
|
|
+AppDB.multilingual.setLanguage('tj')
|
|
|
+
|
|
|
+# Через EventBus
|
|
|
+EventBus.emit('set_language', 'ru')
|
|
|
+```
|
|
|
+
|
|
|
+### Подписка на изменения языка
|
|
|
+```coffee
|
|
|
+# В компоненте
|
|
|
+beforeMount: ->
|
|
|
+ EventBus.on 'language_changed', @handleLanguageChange
|
|
|
+
|
|
|
+methods:
|
|
|
+ handleLanguageChange: (language) ->
|
|
|
+ # Перезагрузка данных на новом языке
|
|
|
+ @loadDataForLanguage(language)
|
|
|
+
|
|
|
+ # Обновление контента
|
|
|
+ @updateContent()
|
|
|
+```
|
|
|
+
|
|
|
+## Методы API
|
|
|
+
|
|
|
+### `setLanguage(languageCode)`
|
|
|
+- **Описание:** Устанавливает указанный язык
|
|
|
+- **Параметры:** `languageCode` - код языка ('ru', 'en', 'tj')
|
|
|
+- **Пример:**
|
|
|
+ ```coffee
|
|
|
+ @$refs.languageSwitcher.setLanguage('en')
|
|
|
+ ```
|
|
|
+
|
|
|
+### `getCurrentLanguage()`
|
|
|
+- **Описание:** Возвращает текущий активный язык
|
|
|
+- **Возвращает:** `String`
|
|
|
+- **Пример:**
|
|
|
+ ```coffee
|
|
|
+ currentLang = @$refs.languageSwitcher.getCurrentLanguage()
|
|
|
+ ```
|
|
|
+
|
|
|
+### `open()`
|
|
|
+- **Описание:** Программно открывает переключатель
|
|
|
+- **Пример:**
|
|
|
+ ```coffee
|
|
|
+ @$refs.languageSwitcher.open()
|
|
|
+ ```
|
|
|
+
|
|
|
+### `close()`
|
|
|
+- **Описание:** Программно закрывает переключатель
|
|
|
+- **Пример:**
|
|
|
+ ```coffee
|
|
|
+ @$refs.languageSwitcher.close()
|
|
|
+ ```
|
|
|
+
|
|
|
+### `getAvailableLanguages()`
|
|
|
+- **Описание:** Возвращает список доступных языков
|
|
|
+- **Возвращает:** `Array`
|
|
|
+- **Пример:**
|
|
|
+ ```coffee
|
|
|
+ languages = @$refs.languageSwitcher.getAvailableLanguages()
|
|
|
+ ```
|
|
|
+
|
|
|
+## Интеграция с мультиязычной системой
|
|
|
+
|
|
|
+### С AppDB
|
|
|
+```coffee
|
|
|
+# Компонент автоматически интегрируется с AppDB.multilingual
|
|
|
+languageSwitcher.setLanguage('en')
|
|
|
+# Эквивалентно:
|
|
|
+AppDB.multilingual.setLanguage('en')
|
|
|
+```
|
|
|
+
|
|
|
+### С глобальным состоянием
|
|
|
+```coffee
|
|
|
+# Изменение языка через компонент обновляет глобальное состояние
|
|
|
+_.changeLanguage('tj')
|
|
|
+```
|
|
|
+
|
|
|
+### С загрузкой данных
|
|
|
+```coffee
|
|
|
+methods:
|
|
|
+ handleLanguageChange: (language) ->
|
|
|
+ # Перезагрузка контента на новом языке
|
|
|
+ promises = [
|
|
|
+ AppDB.getBlogPosts({ language: language })
|
|
|
+ AppDB.getEvents({ language: language })
|
|
|
+ AppDB.getCategories({ language: language })
|
|
|
+ ]
|
|
|
+
|
|
|
+ await Promise.all(promises)
|
|
|
+ EventBus.emit('content_updated')
|
|
|
+```
|
|
|
+
|
|
|
+## Стили и кастомизация
|
|
|
+
|
|
|
+### CSS-классы компонента
|
|
|
+```styl
|
|
|
+.language-switcher
|
|
|
+ // Основной контейнер
|
|
|
+ &__container
|
|
|
+ @apply relative inline-block
|
|
|
+
|
|
|
+ // Кнопка переключателя
|
|
|
+ &__button
|
|
|
+ @apply flex items-center space-x-2 px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors
|
|
|
+
|
|
|
+ // Выпадающий список
|
|
|
+ &__dropdown
|
|
|
+ @apply absolute z-50 mt-2 w-48 bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 py-1
|
|
|
+
|
|
|
+ // Опция языка
|
|
|
+ &__option
|
|
|
+ @apply flex items-center space-x-3 px-4 py-2 text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors cursor-pointer
|
|
|
+
|
|
|
+ &--active
|
|
|
+ @apply bg-blue-50 dark:bg-blue-900 text-blue-600 dark:text-blue-400
|
|
|
+
|
|
|
+ // Вариант с кнопками
|
|
|
+ &--buttons
|
|
|
+ @apply flex space-x-1
|
|
|
+
|
|
|
+ .language-switcher__button
|
|
|
+ @apply rounded-none border-r-0
|
|
|
+
|
|
|
+ &:first-child
|
|
|
+ @apply rounded-l-lg
|
|
|
+
|
|
|
+ &:last-child
|
|
|
+ @apply rounded-r-lg border-r
|
|
|
+
|
|
|
+ // Вариант с флагами
|
|
|
+ &--flags
|
|
|
+ .language-switcher__button
|
|
|
+ @apply p-1
|
|
|
+
|
|
|
+ .language-switcher__option
|
|
|
+ @apply px-3 py-1
|
|
|
+```
|
|
|
+
|
|
|
+### Кастомные стили
|
|
|
+```styl
|
|
|
+// Переопределение стандартных стилей
|
|
|
+.language-switcher--custom
|
|
|
+ .language-switcher__button
|
|
|
+ @apply bg-gradient-to-r from-purple-500 to-pink-500 text-white border-transparent
|
|
|
+
|
|
|
+ &:hover
|
|
|
+ @apply from-purple-600 to-pink-600
|
|
|
+
|
|
|
+ .language-switcher__option
|
|
|
+ &:hover
|
|
|
+ @apply bg-gradient-to-r from-purple-50 to-pink-50 text-purple-700
|
|
|
+
|
|
|
+ &--active
|
|
|
+ @apply bg-gradient-to-r from-purple-100 to-pink-100 text-purple-800
|
|
|
+```
|
|
|
+
|
|
|
+### Темная тема
|
|
|
+```styl
|
|
|
+@media (prefers-color-scheme: dark)
|
|
|
+ .language-switcher
|
|
|
+ &__button
|
|
|
+ @apply bg-gray-800 border-gray-600 text-gray-300
|
|
|
+
|
|
|
+ &:hover
|
|
|
+ @apply bg-gray-700
|
|
|
+
|
|
|
+ &__dropdown
|
|
|
+ @apply bg-gray-800 border-gray-700
|
|
|
+
|
|
|
+ &__option
|
|
|
+ @apply text-gray-300
|
|
|
+
|
|
|
+ &:hover
|
|
|
+ @apply bg-gray-700
|
|
|
+
|
|
|
+ &--active
|
|
|
+ @apply bg-blue-900 text-blue-400
|
|
|
+```
|
|
|
+
|
|
|
+## Особенности работы
|
|
|
+
|
|
|
+### Определение языка по умолчанию
|
|
|
+```coffee
|
|
|
+# Приоритеты определения языка:
|
|
|
+# 1. Сохраненный выбор пользователя (localStorage)
|
|
|
+# 2. Язык браузера
|
|
|
+# 3. Язык по умолчанию (ru)
|
|
|
+```
|
|
|
+
|
|
|
+### Синхронизация между вкладками
|
|
|
+```coffee
|
|
|
+# Слушает события storage для синхронизации
|
|
|
+window.addEventListener('storage', (event) ->
|
|
|
+ if event.key == @storageKey
|
|
|
+ @setLanguage(event.newValue, false) # false - не сохранять снова
|
|
|
+)
|
|
|
+```
|
|
|
+
|
|
|
+### Интеграция с SEO
|
|
|
+```coffee
|
|
|
+methods:
|
|
|
+ updateHtmlLang: (language) ->
|
|
|
+ # Обновление атрибута lang у html элемента
|
|
|
+ document.documentElement.lang = language
|
|
|
+
|
|
|
+ # Обновление hreflang meta-тегов
|
|
|
+ @updateHreflangTags(language)
|
|
|
+```
|
|
|
+
|
|
|
+## Обработка ошибок
|
|
|
+
|
|
|
+### Валидация языка
|
|
|
+```coffee
|
|
|
+# Проверка поддерживаемых языков
|
|
|
+if !@availableLanguages.find((lang) -> lang.code == language)
|
|
|
+ throw new Error("Неподдерживаемый язык: "+language)
|
|
|
+```
|
|
|
+
|
|
|
+### Fallback для localStorage
|
|
|
+```coffee
|
|
|
+try
|
|
|
+ localStorage.setItem(@storageKey, language)
|
|
|
+catch error
|
|
|
+ # Используем cookie как fallback
|
|
|
+ document.cookie = @storageKey+"="+language+"; path=/; max-age=31536000"
|
|
|
+```
|
|
|
+
|
|
|
+## Примеры интеграции
|
|
|
+
|
|
|
+### 1. С аналитикой
|
|
|
+```coffee
|
|
|
+methods:
|
|
|
+ handleLanguageChange: ({ language, previousLanguage }) ->
|
|
|
+ # Отправка в аналитику
|
|
|
+ gtag('event', 'language_change', {
|
|
|
+ event_category: 'ui',
|
|
|
+ event_label: language,
|
|
|
+ value: 1
|
|
|
+ })
|
|
|
+```
|
|
|
+
|
|
|
+### 2. С синхронизацией с сервером
|
|
|
+```coffee
|
|
|
+methods:
|
|
|
+ handleLanguageChange: (language) ->
|
|
|
+ # Сохранение на сервере (если пользователь авторизован)
|
|
|
+ if @user
|
|
|
+ await @api.saveUserPreferences({ language: language })
|
|
|
+```
|
|
|
+
|
|
|
+### 3. С динамической загрузкой переводов
|
|
|
+```coffee
|
|
|
+methods:
|
|
|
+ handleLanguageChange: (language) ->
|
|
|
+ # Загрузка файлов переводов
|
|
|
+ try
|
|
|
+ translations = await import('../locales/'+language+'.json')
|
|
|
+ AppDB.multilingual.setTranslations(language, translations)
|
|
|
+ catch error
|
|
|
+ debug.log "Ошибка загрузки переводов: "+error
|
|
|
+```
|
|
|
+
|
|
|
+## Best Practices
|
|
|
+
|
|
|
+### 1. Всегда предоставляйте понятные названия
|
|
|
+```pug
|
|
|
+//- Правильно - показываем родные названия
|
|
|
+language-switcher(showNativeNames="true")
|
|
|
+
|
|
|
+//- Неправильно - только коды
|
|
|
+language-switcher(:showNativeNames="false")
|
|
|
+```
|
|
|
+
|
|
|
+### 2. Используйте флаги аккуратно
|
|
|
+```pug
|
|
|
+//- Флаги помогают визуальной идентификации
|
|
|
+language-switcher(showFlags="true")
|
|
|
+
|
|
|
+//- Но могут быть спорными для некоторых языков
|
|
|
+```
|
|
|
+
|
|
|
+### 3. Сохраняйте состояние пользователя
|
|
|
+```pug
|
|
|
+//- Автоматически сохраняет в localStorage
|
|
|
+language-switcher
|
|
|
+```
|
|
|
+
|
|
|
+### 4. Обеспечивайте доступность
|
|
|
+```pug
|
|
|
+//- Правильные ARIA-атрибуты
|
|
|
+language-switcher(aria-label="Переключение языка")
|
|
|
+```
|
|
|
+
|
|
|
+### 5. Тестируйте все варианты
|
|
|
+```coffee
|
|
|
+# В тестах
|
|
|
+describe('LanguageSwitcher', ->
|
|
|
+ it('should switch between languages', ->
|
|
|
+ switcher.setLanguage('en')
|
|
|
+ expect(switcher.getCurrentLanguage()).toBe('en')
|
|
|
+
|
|
|
+ switcher.setLanguage('ru')
|
|
|
+ expect(switcher.getCurrentLanguage()).toBe('ru')
|
|
|
+ )
|
|
|
+)
|
|
|
+```
|
|
|
+
|
|
|
+### 6. Учитывайте RTL языки
|
|
|
+```coffee
|
|
|
+methods:
|
|
|
+ handleLanguageChange: (language) ->
|
|
|
+ # Для RTL языков (арабский, иврит и т.д.)
|
|
|
+ if @isRtlLanguage(language)
|
|
|
+ document.documentElement.dir = 'rtl'
|
|
|
+ else
|
|
|
+ document.documentElement.dir = 'ltr'
|
|
|
+```
|
|
|
+
|
|
|
+Компонент LanguageSwitcher предоставляет полнофункциональное решение для управления языками в мультиязычном приложении с поддержкой доступности, сохранения состояния и интеграции с глобальной системой мультиязычности.
|