refactor: simplify translations — shared utils, deduplicated code

- Extract shared constants to client/src/utils/translations.js
  (AVAILABLE_LANGUAGES, TRANSLATION_STATUS_COLORS, isTextSelected, groupTextsByLanguage)
- TranslationDetailPanel: deduplicate copy button JSX, hoist hasSelected
- PublicTranslationReview: memoize textsByLanguage, use shared isTextSelected
- Translations page: import from shared module
- Server: translation schema updates, post_id linking
- Add reassign-user utility script
- Add new translation i18n keys to en.json and ar.json

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
fahed
2026-03-11 17:27:57 +03:00
parent 7ace32a070
commit ba3900bc33
8 changed files with 826 additions and 193 deletions
+30
View File
@@ -0,0 +1,30 @@
export const AVAILABLE_LANGUAGES = [
{ code: 'AR', label: 'العربية' },
{ code: 'EN', label: 'English' },
{ code: 'FR', label: 'Français' },
{ code: 'ID', label: 'Bahasa Indonesia' },
]
export const TRANSLATION_STATUS_COLORS = {
draft: 'bg-surface-tertiary text-text-secondary',
pending_review: 'bg-amber-100 text-amber-700',
approved: 'bg-emerald-100 text-emerald-700',
rejected: 'bg-red-100 text-red-700',
revision_requested: 'bg-orange-100 text-orange-700',
}
export function isTextSelected(text) {
return text.is_selected === true || text.is_selected === 1
}
export function groupTextsByLanguage(texts) {
const grouped = {}
for (const text of texts) {
if (!grouped[text.language_code]) grouped[text.language_code] = []
grouped[text.language_code].push(text)
}
for (const code in grouped) {
grouped[code].sort((a, b) => (a.option_number || 1) - (b.option_number || 1))
}
return grouped
}