@@ -2,7 +2,11 @@ import { css } from "@emotion/react";
22
33import React from "react" ;
44import { CheapCard } from "./CheapCard" ;
5- import { ILanguage , getDisplayNamesForLanguage } from "../model/Language" ;
5+ import {
6+ ILanguage ,
7+ getDisplayNamesForLanguage ,
8+ kTagForNoLanguage ,
9+ } from "../model/Language" ;
610import { commonUI } from "../theme" ;
711import { useResponsiveChoice } from "../responsiveUtilities" ;
812import { FormattedMessage } from "react-intl" ;
@@ -43,13 +47,48 @@ export const LanguageCard: React.FunctionComponent<
4347 ...propsToPassDown
4448 } = props ; // Prevent React warnings
4549
46- const { primary , secondary } = getDisplayNamesForLanguage ( props ) ;
50+ const displayNames = getDisplayNamesForLanguage ( props ) ;
4751 const getResponsiveChoice = useResponsiveChoice ( ) ;
4852 const { cardWidthPx, cardHeightPx } = useLanguageCardSpec ( props . larger ) ;
4953 const urlPrefix = props . targetPrefix ?? "/language:" ;
5054 const showCount = ! useIsAppHosted ( ) ;
5155 const cardSpacing = useBaseCardSpec ( ) . cardSpacingPx ;
5256
57+ const isPictureBook = isoCode === kTagForNoLanguage ;
58+
59+ // BL-15812 Prefer the autonym as the primary label; fall back to existing display logic
60+ // for picture books or other special cases where autonym can be empty.
61+ const primary = isPictureBook
62+ ? displayNames . primary
63+ : displayNames . autonym . trim ( )
64+ ? displayNames . autonym
65+ : displayNames . primary ;
66+
67+ // Build the gray header labels explicitly so English and the tag can be separate lines.
68+ const secondaryLinesToRender : string [ ] = [ ] ;
69+ if ( isPictureBook ) {
70+ // Preserve the historical duplication for picture-book cards.
71+ secondaryLinesToRender . push ( displayNames . primary ) ;
72+ } else {
73+ if ( englishName && englishName !== primary ) {
74+ secondaryLinesToRender . push ( englishName ) ;
75+ }
76+ // The logic that generates otherSecondaryNames makes sure it is not the same
77+ // as primary or english names. Currently, it will be the language tag if
78+ // getDisplayNamesForLanguage decides it adds something useful to the english name.
79+ if ( displayNames . otherSecondaryNames ) {
80+ secondaryLinesToRender . push ( displayNames . otherSecondaryNames ) ;
81+ }
82+ }
83+ const secondaryLineText = secondaryLinesToRender . join ( " " ) ;
84+ const hasMultipleSecondaryLines = secondaryLinesToRender . length > 1 ;
85+ // Only used for the single-line case, where we can allow two lines of wrap.
86+ const shouldTruncateSecondary = secondaryLineText . length >= 18 ;
87+ const [
88+ secondaryPrimaryLine ,
89+ ...secondaryRemainingLines
90+ ] = secondaryLinesToRender ;
91+
5392 // In the main website, we want language cards to be responsive: smaller and with smaller text on small screens.
5493 // In the language chooser intended to be embedded in BloomReader, we want larger sizes.
5594 // The description said "about a third larger" which happens to be, for most measurements, what the large-screen
@@ -119,12 +158,25 @@ export const LanguageCard: React.FunctionComponent<
119158 line-height : 1em ;
120159 ` }
121160 >
122- < SmartTruncateMarkup
123- condition = { ( secondary ?? "" ) . length >= 18 }
124- lines = { 2 }
125- >
126- < span > { secondary } </ span >
127- </ SmartTruncateMarkup >
161+ { secondaryLinesToRender . length > 0 &&
162+ ( hasMultipleSecondaryLines ? (
163+ < React . Fragment >
164+ { /* Clamp the first line so the tag line always stays visible. */ }
165+ < SmartTruncateMarkup condition = { true } lines = { 1 } >
166+ < span > { secondaryPrimaryLine } </ span >
167+ </ SmartTruncateMarkup >
168+ { secondaryRemainingLines . map ( ( line , index ) => (
169+ < div key = { `${ line } -${ index } ` } > { line } </ div >
170+ ) ) }
171+ </ React . Fragment >
172+ ) : (
173+ < SmartTruncateMarkup
174+ condition = { shouldTruncateSecondary }
175+ lines = { 2 }
176+ >
177+ < span > { secondaryPrimaryLine } </ span >
178+ </ SmartTruncateMarkup >
179+ ) ) }
128180 </ div >
129181 </ div >
130182 < h2
0 commit comments