🌎 i18n: React-i18next & i18next Integration (#5720)

* better i18n support an internationalization-framework.

* removed unused package

* auto sort for translation.json

* fixed tests with the new locales function

* added new CI actions from locize

* to use locize a mention in the README.md

* to use locize a mention in the README.md

* updated README.md and added TRANSLATION.md to the repo

* updated TRANSLATION.md badges

* updated README.md to go to the TRANSLATION.md when clicking on the Translation Progress badge

* updated TRANSLATION.md and added a new issue template.

* updated TRANSLATION.md and added a new issue template.

* updated issue template to add the iso code link.

* updated the new GitHub actions for `locize`

* updated label for new issue template --> i18n

* fixed type issue

* Fix eslint

* Fix eslint with key-spacing spacing

* fix: error type

* fix: handle undefined values in SortFilterHeader component

* fix: typing in Image component

* fix: handle optional promptGroup in PromptCard component

* fix: update localize function to accept string type and remove unnecessary JSX element

* fix: update localize function to enforce TranslationKeys type for better type safety

* fix: improve type safety and handle null values in Assistants component

* fix: enhance null checks for fileId in FilesListView component

* fix: localize 'Go back' button text in FilesListView component

* fix: update aria-label for menu buttons and add translation for 'Close Menu'

* docs: add Reasoning UI section for Chain-of-Thought AI models in README

* fix: enhance type safety by adding type for message in MultiMessage component

* fix: improve null checks and optional chaining in useAutoSave hook

* fix: improve handling of optional properties in cleanupPreset function

* fix: ensure isFetchingNextPage defaults to false and improve null checks for messages in Search component

* fix: enhance type safety and null checks in useBuildMessageTree hook

---------

Co-authored-by: Danny Avila <danny@librechat.ai>
This commit is contained in:
Ruben Talstra 2025-02-09 18:05:31 +01:00 committed by GitHub
parent 2e8d969e35
commit aae413cc71
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
153 changed files with 13448 additions and 38224 deletions

View file

@ -0,0 +1,33 @@
name: New Language Request
description: Request to add a new language for LibreChat translations.
title: "New Language Request: "
labels: ["enhancement", "i18n"]
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to submit a new language request! Please fill out the following details so we can review your request.
- type: input
id: language_name
attributes:
label: Language Name
description: Please provide the full name of the language (e.g., Spanish, Mandarin).
placeholder: e.g., Spanish
validations:
required: true
- type: input
id: iso_code
attributes:
label: ISO 639-1 Code
description: Please provide the ISO 639-1 code for the language (e.g., es for Spanish). You can refer to [this list](https://www.w3schools.com/tags/ref_language_codes.asp) for valid codes.
placeholder: e.g., es
validations:
required: true
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/danny-avila/LibreChat/blob/main/.github/CODE_OF_CONDUCT.md).
options:
- label: I agree to follow this project's Code of Conduct
required: true

70
.github/TRANSLATION.md vendored Normal file
View file

@ -0,0 +1,70 @@
# LibreChat Translation Guide
Thank you for your interest in translating LibreChat! We rely on community contributions to make our application accessible to users around the globe. We manage all translations using [Locize](https://locize.com), a powerful translation management system that integrates seamlessly with our project.
## How Translations Work
- **Centralized Management:** All translation strings for LibreChat are managed in a single location on Locize. This allows us to keep translations consistent across all parts of the application.
- **Automatic Updates:** Changes made in Locize are automatically synchronized with our project. You can see the current translation progress for each language via the dynamic badges in our GitHub repository.
- **Community Driven:** We welcome contributions in all languages. Your help ensures that more users can enjoy LibreChat in their native language.
## Getting Started
### 1. Create a Locize Account
If you don't already have an account, please register using our invite link:
[Register at Locize](https://www.locize.app/register?invitation=t1VDfqoRvj8eUkd1JasxxrBCCI4SAqeeofa2YumAgmVDRxkr4vO1jKqNmpaNCv7H)
This invitation will give you access to our translation project once youve created your account.
## Adding a New Language
If you do not see your language listed in our current translation table, please help us expand our language support by following these steps:
1. **Create a New Issue:** Open a new issue in the GitHub repository.
2. **Use the Template:** When creating your issue, please select the **New Language Request** template. This template will guide you through providing all the necessary details, including:
- The full name of your language (e.g., Spanish, Mandarin).
- The [ISO 639-1](https://www.w3schools.com/tags/ref_language_codes.asp) code for your language (e.g., es for Spanish).
3. **Collaborate with Maintainers:** Our maintainers will review your issue and work with you to integrate the new language. Once approved, your language will appear in the translation progress table, and you can start contributing translations.
## Translation Progress
Below is our current translation progress for some of the supported languages. Feel free to check these badges and help us improve the translations further:
| Language | Translation Progress Badge |
|---------------------------------------|----------------------------|
| **English (en)** | ![EN Badge](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&color=2096F3&label=Locize&query=%24.versions%5B'latest'%5D.languages%5B'en'%5D.translatedPercentage&url=https://api.locize.app/badgedata/4cb2598b-ed4d-469c-9b04-2ed531a8cb45&suffix=%+translated&link=https://www.locize.com&prefix=EN:+) |
| **Arabic (ar)** | ![AR Badge](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&color=2096F3&label=Locize&query=%24.versions%5B'latest'%5D.languages%5B'ar'%5D.translatedPercentage&url=https://api.locize.app/badgedata/4cb2598b-ed4d-469c-9b04-2ed531a8cb45&suffix=%+translated&link=https://www.locize.com&prefix=AR:+) |
| **German (de)** | ![DE Badge](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&color=2096F3&label=Locize&query=%24.versions%5B'latest'%5D.languages%5B'de'%5D.translatedPercentage&url=https://api.locize.app/badgedata/4cb2598b-ed4d-469c-9b04-2ed531a8cb45&suffix=%+translated&link=https://www.locize.com&prefix=DE:+) |
| **Spanish (es)** | ![ES Badge](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&color=2096F3&label=Locize&query=%24.versions%5B'latest'%5D.languages%5B'es'%5D.translatedPercentage&url=https://api.locize.app/badgedata/4cb2598b-ed4d-469c-9b04-2ed531a8cb45&suffix=%+translated&link=https://www.locize.com&prefix=ES:+) |
| **Finnish (fi)** | ![FI Badge](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&color=2096F3&label=Locize&query=%24.versions%5B'latest'%5D.languages%5B'fi'%5D.translatedPercentage&url=https://api.locize.app/badgedata/4cb2598b-ed4d-469c-9b04-2ed531a8cb45&suffix=%+translated&link=https://www.locize.com&prefix=FI:+) |
| **French (fr)** | ![FR Badge](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&color=2096F3&label=Locize&query=%24.versions%5B'latest'%5D.languages%5B'fr'%5D.translatedPercentage&url=https://api.locize.app/badgedata/4cb2598b-ed4d-469c-9b04-2ed531a8cb45&suffix=%+translated&link=https://www.locize.com&prefix=FR:+) |
| **Hebrew (he)** | ![HE Badge](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&color=2096F3&label=Locize&query=%24.versions%5B'latest'%5D.languages%5B'he'%5D.translatedPercentage&url=https://api.locize.app/badgedata/4cb2598b-ed4d-469c-9b04-2ed531a8cb45&suffix=%+translated&link=https://www.locize.com&prefix=HE:+) |
| **Indonesian (id)** | ![ID Badge](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&color=2096F3&label=Locize&query=%24.versions%5B'latest'%5D.languages%5B'id'%5D.translatedPercentage&url=https://api.locize.app/badgedata/4cb2598b-ed4d-469c-9b04-2ed531a8cb45&suffix=%+translated&link=https://www.locize.com&prefix=ID:+) |
| **Italian (it)** | ![IT Badge](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&color=2096F3&label=Locize&query=%24.versions%5B'latest'%5D.languages%5B'it'%5D.translatedPercentage&url=https://api.locize.app/badgedata/4cb2598b-ed4d-469c-9b04-2ed531a8cb45&suffix=%+translated&link=https://www.locize.com&prefix=IT:+) |
| **Japanese (ja)** | ![JA Badge](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&color=2096F3&label=Locize&query=%24.versions%5B'latest'%5D.languages%5B'ja'%5D.translatedPercentage&url=https://api.locize.app/badgedata/4cb2598b-ed4d-469c-9b04-2ed531a8cb45&suffix=%+translated&link=https://www.locize.com&prefix=JA:+) |
| **Korean (ko)** | ![KO Badge](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&color=2096F3&label=Locize&query=%24.versions%5B'latest'%5D.languages%5B'ko'%5D.translatedPercentage&url=https://api.locize.app/badgedata/4cb2598b-ed4d-469c-9b04-2ed531a8cb45&suffix=%+translated&link=https://www.locize.com&prefix=KO:+) |
| **Dutch (nl)** | ![NL Badge](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&color=2096F3&label=Locize&query=%24.versions%5B'latest'%5D.languages%5B'nl'%5D.translatedPercentage&url=https://api.locize.app/badgedata/4cb2598b-ed4d-469c-9b04-2ed531a8cb45&suffix=%+translated&link=https://www.locize.com&prefix=NL:+) |
| **Polish (pl)** | ![PL Badge](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&color=2096F3&label=Locize&query=%24.versions%5B'latest'%5D.languages%5B'pl'%5D.translatedPercentage&url=https://api.locize.app/badgedata/4cb2598b-ed4d-469c-9b04-2ed531a8cb45&suffix=%+translated&link=https://www.locize.com&prefix=PL:+) |
| **Portuguese (pt)** | ![PT Badge](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&color=2096F3&label=Locize&query=%24.versions%5B'latest'%5D.languages%5B'pt'%5D.translatedPercentage&url=https://api.locize.app/badgedata/4cb2598b-ed4d-469c-9b04-2ed531a8cb45&suffix=%+translated&link=https://www.locize.com&prefix=PT:+) |
| **Russian (ru)** | ![RU Badge](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&color=2096F3&label=Locize&query=%24.versions%5B'latest'%5D.languages%5B'ru'%5D.translatedPercentage&url=https://api.locize.app/badgedata/4cb2598b-ed4d-469c-9b04-2ed531a8cb45&suffix=%+translated&link=https://www.locize.com&prefix=RU:+) |
| **Swedish (sv)** | ![SV Badge](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&color=2096F3&label=Locize&query=%24.versions%5B'latest'%5D.languages%5B'sv'%5D.translatedPercentage&url=https://api.locize.app/badgedata/4cb2598b-ed4d-469c-9b04-2ed531a8cb45&suffix=%+translated&link=https://www.locize.com&prefix=SV:+) |
| **Turkish (tr)** | ![TR Badge](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&color=2096F3&label=Locize&query=%24.versions%5B'latest'%5D.languages%5B'tr'%5D.translatedPercentage&url=https://api.locize.app/badgedata/4cb2598b-ed4d-469c-9b04-2ed531a8cb45&suffix=%+translated&link=https://www.locize.com&prefix=TR:+) |
| **Vietnamese (vi)** | ![VI Badge](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&color=2096F3&label=Locize&query=%24.versions%5B'latest'%5D.languages%5B'vi'%5D.translatedPercentage&url=https://api.locize.app/badgedata/4cb2598b-ed4d-469c-9b04-2ed531a8cb45&suffix=%+translated&link=https://www.locize.com&prefix=VI:+) |
| **Chinese (Simplified) (zh)** | ![ZH Badge](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&color=2096F3&label=Locize&query=%24.versions%5B'latest'%5D.languages%5B'zh'%5D.translatedPercentage&url=https://api.locize.app/badgedata/4cb2598b-ed4d-469c-9b04-2ed531a8cb45&suffix=%+translated&link=https://www.locize.com&prefix=ZH:+) |
| **Chinese (Traditional) (zh-Hant)** | ![ZH-HANT Badge](https://img.shields.io/badge/dynamic/json.svg?style=for-the-badge&color=2096F3&label=Locize&query=%24.versions%5B'latest'%5D.languages%5B'zh-Hant'%5D.translatedPercentage&url=https://api.locize.app/badgedata/4cb2598b-ed4d-469c-9b04-2ed531a8cb45&suffix=%+translated&link=https://www.locize.com&prefix=ZH-HANT:+) |
---
## Need Help?
If you have any questions about the translation process or need assistance getting started, please feel free to:
- Open an issue in this repository.
- Join our [Discord community](https://discord.librechat.ai) to chat with fellow translators and contributors.
- Contact one of the project maintainers directly.
Your contributions help make LibreChat better for users worldwide. Happy translating!

View file

@ -0,0 +1,53 @@
name: Locize Version Published Workflow
on:
push:
branches: [main]
repository_dispatch:
types: [locize/versionPublished]
jobs:
locize_update:
name: Process Locize Version Published Event
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Display Dispatch Payload
run: |
echo "Received Version: ${{ github.event.client_payload.payload.version }}"
echo "Full Payload: ${{ toJson(github.event.client_payload) }}"
- name: Download Translations from locize
uses: locize/download@v1
with:
project-id: ${{ secrets.LOCIZE_PROJECT_ID }}
version: ${{ github.event.client_payload.payload.version }}
path: "client/src/locales"
path-mask: "{{language}}/{{namespace}}"
clean: true # Ensures old translation files are removed before downloading new ones
- name: Create Pull Request
id: create_pr
uses: peter-evans/create-pull-request@v7.0.6
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "chore: update translations from locize"
branch: locize-update-${{ github.event.client_payload.payload.version }}
delete-branch: true
title: "chore: update translations from locize"
body: |
This PR updates translations from locize.
- Version: `${{ github.event.client_payload.payload.version }}`
- Automated update from GitHub Actions
labels: "translations, automated"
draft: false
- name: Check PR Outputs
if: steps.create_pr.outputs.pull-request-number
run: |
echo "Pull Request Number - ${{ steps.create_pr.outputs.pull-request-number }}"
echo "Pull Request URL - ${{ steps.create_pr.outputs.pull-request-url }}"

View file

@ -0,0 +1,26 @@
name: Push New Keys to locize
on:
push:
branches: [main]
jobs:
push-new-keys:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Set Up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install locize CLI
run: npm install -g locize-cli
- name: Push Missing Translation Keys to locize
run: |
cd client/src/locales
locize save-missing --api-key ${{ secrets.LOCIZE_API_KEY }} --project-id ${{ secrets.LOCIZE_PROJECT_ID }} --language en