Use frontend translations for OCR language picker (#5051)

## Summary
- revert OCR ui-data endpoint to only expose language codes without
backend labels
- translate OCR language options on the frontend using existing lang.*
keys with locale-aware fallbacks

## Testing
- Not run (not requested)


------
[Codex
Task](https://chatgpt.com/codex/tasks/task_b_6928ae7c85448328a0d2660a0c021b22)
This commit is contained in:
Anthony Stirling
2025-11-29 16:05:15 +00:00
committed by GitHub
parent 85e9121745
commit fde449e738
@@ -1,7 +1,8 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { Text, Loader } from '@mantine/core'; import { Text, Loader } from '@mantine/core';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { tempOcrLanguages, getAutoOcrLanguage } from '@app/utils/languageMapping'; import { getAutoOcrLanguage, getBrowserLanguagesForOcr, getOcrDisplayName } from '@app/utils/languageMapping';
import apiClient from '@app/services/apiClient';
import DropdownListWithFooter, { DropdownItem } from '@app/components/shared/DropdownListWithFooter'; import DropdownListWithFooter, { DropdownItem } from '@app/components/shared/DropdownListWithFooter';
export interface LanguageOption { export interface LanguageOption {
@@ -37,32 +38,41 @@ const LanguagePicker: React.FC<LanguagePickerProps> = ({
// Fetch available languages from backend // Fetch available languages from backend
const fetchLanguages = async () => { const fetchLanguages = async () => {
try { try {
const response = await fetch(languagesEndpoint); const { data } = await apiClient.get<{ languages: string[] }>(languagesEndpoint);
const displayNames = typeof Intl.DisplayNames !== 'undefined'
? new Intl.DisplayNames([i18n.language], { type: 'language' })
: null;
if (response.ok) { const languageOptions = [...new Set(data.languages)]
const data: { languages: string[] } = await response.json(); .map((lang) => {
const languages = data.languages; const displayName = getOcrDisplayName(lang);
const browserLanguageCodes = getBrowserLanguagesForOcr(lang);
const langKey = `lang.${lang}`;
const translatedFromKey = t(langKey);
const hasKeyTranslation = translatedFromKey !== langKey;
const languageOptions = languages.map(lang => { const intlTranslatedName = displayNames
// TODO: Use actual language translations when they become available ? browserLanguageCodes
// For now, use temporary English translations .map((code) => displayNames.of(code))
const translatedName = tempOcrLanguages.lang[lang as keyof typeof tempOcrLanguages.lang] || lang; .find((name): name is string => Boolean(name))
const displayName = translatedName; : null;
const translatedName =
(hasKeyTranslation ? translatedFromKey : null)
|| intlTranslatedName
|| t(`ocr.languages.${lang}`, displayName);
return { return {
value: lang, value: lang,
name: displayName name: translatedName,
label: translatedName
}; };
}); })
.sort((a, b) => a.name.localeCompare(b.name, i18n.language));
setAvailableLanguages(languageOptions); setAvailableLanguages(languageOptions);
} else {
console.error('[LanguagePicker] Response not OK:', response.status, response.statusText);
const errorText = await response.text();
console.error('[LanguagePicker] Error response body:', errorText);
}
} catch (error) { } catch (error) {
console.error('[LanguagePicker] Fetch failed with error:', error); console.error('[LanguagePicker] Fetch failed with error:', error);
console.error('[LanguagePicker] Error details:', { console.error('[LanguagePicker] Error details:', {
@@ -76,7 +86,7 @@ const LanguagePicker: React.FC<LanguagePickerProps> = ({
}; };
fetchLanguages(); fetchLanguages();
}, [languagesEndpoint]); }, [languagesEndpoint, i18n.language, t]);
// Auto-fill OCR language based on browser language when languages are loaded // Auto-fill OCR language based on browser language when languages are loaded
useEffect(() => { useEffect(() => {