Flutter 다국어 UI를 검증했더니 ‘300 BPM’이 두 줄로 나뉘어 있었다
SANGE 메트로놈에서 12개 언어·6개 화면 크기·3단계 글자 배율을 조합한 표시 테스트를 진행했습니다. ‘300 BPM’의 줄바꿈과 긴 오류 메시지를 계기로 UI를 수정하고 자동 테스트의 확인 항목을 검토한 기록입니다.
개인 개발 중인 ‘SANGE 메트로놈 – 간편한 리듬 연습’에서 작은 화면과 큰 글자 설정의 표시를 검증했습니다.
그 과정에서 즐겨찾기에 표시되는 ‘300 BPM’의 숫자가 ‘30’과 ‘0’으로 나뉘는 문제가 발견되었습니다. 글자가 화면 밖으로 넘치는 것은 아니었습니다. 그래도 템포 값으로는 읽기 어려운 표시였습니다.
레이아웃 예외가 발생하지 않는 것과 필요한 정보를 읽을 수 있는 것은 각각 확인해야 했습니다.
이번에는 12개 언어의 Widget 테스트와 Android 에뮬레이터의 화면 확인을 통해 어떤 표시 문제가 발견되었고, 수정과 테스트에 어떻게 반영했는지 정리합니다.

일본어로 들어간다고 같은 배치를 쓸 수 있는 것은 아니다
메트로놈 화면에는 템포 숫자뿐 아니라 박자 수, 리듬 이름, 음량, 즐겨찾기 이름 등을 표시합니다. 저장 화면에는 입력란, 오류 설명, 저장·취소 버튼도 필요합니다.
일본어로 확인했을 때 들어가던 배치도 번역하면 라벨 길이가 달라집니다. 예를 들어 일본어 ‘12拍’와 독일어 ‘12 Schläge’는 버튼에 필요한 너비가 다릅니다.
글자를 더 크게 하면 가로로 나란히 배치한 요소들이 들어가지 않게 됩니다. 그래서 언어만 전환하는 대신 화면 크기·글자 배율·표시할 화면을 조합하여 확인하기로 했습니다.
12개 언어·6개 크기·3단계 글자 배율로 자동 검증
Widget 테스트에서는 다음 조건을 조합했습니다. Widget 테스트는 테스트 환경에서 Flutter 화면 구성 요소를 렌더링하여 확인하는 방법입니다.
| 확인 기준 | 조건 |
|---|---|
| 언어 | 일본어, 영어, 스페인어, 브라질 포르투갈어, 독일어, 프랑스어, 한국어, 인도네시아어, 베트남어, 태국어, 번체 중국어, 이탈리아어 |
| 논리 크기·세로 방향 | 320×568、360×640、360×800、393×873、412×915、432×960 |
| 글자 배율 | 100%·130%·200% |
| 화면 | 홈, 박자 수, 리듬 세분화, 설정, 언어 선택, 저장, 즐겨찾기 관리, 즐겨찾기 목록 |
12개 언어 × 6개 크기 × 3단계 글자 배율 × 8개 화면 = 1,728개 조건
테스트 데이터로 300 BPM, 12박, 16분음표, 음량 100%, 긴 이름의 즐겨찾기 3개를 설정했습니다. 저장 화면에는 이름 중복 오류도 표시했습니다.
글자 배율은 TextScaler.linear로 지정했습니다. 이번 100%·130%·200%는 선형으로 확대하는 테스트 조건이며, 실제 기기의 OS 설정에 따른 글자 확대를 모두 그대로 재현한 것은 아닙니다.
Android 에뮬레이터에서도 이미지를 수집했습니다. 대상은 독일어, 프랑스어, 브라질 포르투갈어, 인도네시아어, 태국어, 베트남어, 일본어의 7개 언어입니다. 모든 크기·배율·언어를 전부 조합한 것은 아닙니다. 독일어로 화면 크기와 글자 배율을 확인하고, 나머지 6개 언어는 360×640 설정·130%로 확인했습니다.
에뮬레이터에서는 시스템 바 영역만큼 앱이 사용할 수 있는 영역이 작아집니다. 설정한 크기뿐 아니라 렌더링 시 논리 크기와 SafeArea 내부 크기도 기록했습니다.
박자 수 버튼은 글자가 들어가는 열 수로 바꾼다
처음 발견한 문제는 템포 설명과 박자 수 단위가 오른쪽으로 넘치는 현상이었습니다. Android 에뮬레이터에서는 RenderFlex overflow도 검출되어 레이아웃을 다시 검토해야 했습니다.
박자 수 선택 버튼에는 4열 고정 배치도 있었습니다. 하지만 번역된 라벨이 길어지거나 글자 배율이 커지면 그 열 수로는 너비가 부족해집니다.
그래서 번역된 라벨을 TextPainter로 측정하고, 글자 배율을 포함해 필요한 너비를 기준으로 열 수를 정하도록 했습니다. 좁은 조건에서는 열 수를 줄여 세로로 배치합니다.


홈 화면에서도 긴 리듬 이름을 좁은 2열에 넣던 배치를 검토하고, 필요에 따라 박자 수와 리듬을 세로로 배치했습니다. 홈의 10~12박 숫자가 나뉘는 문제는 박 표시 전체가 여러 줄로 줄바꿈되도록 하여 해결했습니다.
‘300’이 나뉘어도 예외가 발생하는 것은 아니다
이미지를 확인하던 중 발견한 것은 320×568 표시 설정·글자 배율 200%의 즐겨찾기 카드였습니다.
카드를 3열로 유지했기 때문에 ‘300’ 중간에서 줄바꿈이 일어났습니다. 글자가 표시 영역 안에 들어가더라도 숫자가 ‘30’과 ‘0’으로 나뉘면 템포 값을 읽기 어려워집니다.
이 문제는 레이아웃 예외 검사만으로는 검출할 수 없었습니다.
수정 시에는 글자 배율에 맞추어 즐겨찾기 카드의 열 수를 조정했습니다. 이번의 작은 화면·200% 표시에서는 1열로 하여 템포 숫자가 중간에서 나뉘지 않게 했습니다.

수정과 함께 자동 테스트에 ‘세 자리 BPM이 한 줄에 들어갈 것’이라는 확인을 추가했습니다. 다음은 해당 확인 부분의 발췌입니다.
for (var card = 0; card < 3; card++) {
final paragraph = tester.renderObject<RenderParagraph>(
find.text('300 BPM').at(card),
);
expect(
paragraph.getBoxesForSelection(
const TextSelection(baseOffset: 0, extentOffset: 3),
),
hasLength(1),
reason:
'$locale/$size/$scale favorite BPM must stay on one line',
);
}
‘300’에 해당하는 문자 범위의 렌더링 박스가 하나인지 확인합니다. 실제 테스트에서는 즐겨찾기 3개의 BPM 각각과 홈 화면의 1~12 박 번호를 확인했습니다.
이 방법은 이번에 동일한 글꼴로 렌더링하는 숫자를 대상으로 합니다. 서로 다른 언어나 글꼴이 섞인 문장의 줄바꿈을 일반적으로 판별하기 위한 방법은 아닙니다.
표시하려는 정보에 맞게 확인 항목을 구체화한다. 이미지에서 발견한 문제를 다음 변경에서도 검출할 수 있는 자동 테스트에 반영한 것이 이번 검증의 성과였습니다.
오류 설명과 저장 버튼까지 도달할 수 있는가
저장 화면에서는 오류 메시지의 줄 수 제한도 검토했습니다.
원래는 최대 3줄로 제한했지만, 좁은 화면에서 글자를 키우면 긴 번역문이 들어가지 않을 수 있었습니다. 따라서 줄 수 상한을 없애고 스크롤하여 설명 전체를 읽을 수 있게 했습니다.
저장·취소 버튼은 좁은 화면이나 큰 글자 설정에서 세로로 배치하도록 변경했습니다. 모달의 제목과 닫기 버튼, 설정 이름과 선택된 값도 글자에 필요한 너비를 확보하는 배치로 변경했습니다.

입력 중 확인도 추가했습니다. Widget 테스트에서는 키보드에 해당하는 아래쪽 여백을 280 논리 픽셀로 두고, 스크롤 후 저장 버튼이 해당 영역 위에 표시되는지 확인했습니다. 오류 메시지가 줄 수 제한으로 생략되지 않는지도 확인했습니다.
Android 에뮬레이터에서는 실제로 입력란에 포커스를 두고 키보드가 표시된 상태의 배치를 확인했습니다. 다만 이때 수집한 PNG는 Flutter 화면만 캡처한 것으로, OS 키보드 자체는 찍히지 않습니다. 일반 표시와 입력 중 이미지는 구분하여 기록했습니다.
수정 후 결과와 확인한 범위
2026년 10월 30일의 검증 결과는 다음과 같습니다.
| 품목 | 결과 |
|---|---|
| 표시 Widget 테스트 | 1,728개 조건에서 레이아웃 예외 없음. 해당 화면에서 숫자 줄바꿈, 오류 메시지 생략, 저장 버튼 접근성 확인도 통과 |
| 전체 Flutter 테스트 | 121개 통과 |
| 정적 분석 | 지적 사항 없음 |
| Android 에뮬레이터의 화면 조건 | 280개 조건. 각 실행의 layoutErrors 는 0건 |
| 수집한 PNG | 스크롤 후·입력 중 이미지를 포함한 478개 |
1,728은 표시 조건의 조합 수이며, 121은 전체 Flutter 테스트의 실행 건수입니다. 테스트 안에서 여러 표시 조건을 반복 확인하므로 서로 다른 수치로 구분합니다.
478은 수집한 PNG의 개수입니다. 모든 이미지에 개별적으로 육안 합격·불합격 판정을 내린 것은 아니며, 주요 화면을 골라 글자 잘림과 겹침, 숫자 분할, 스크롤 후 표시를 확인했습니다. 태국어·베트남어도 확인한 주요 화면에서는 누락 글리프를 나타내는 네모나 글자 겹침이 보이지 않았습니다.
에뮬레이터에서는 합성 크기 6종류에 더해 Galaxy A16 5G·A06 4G·S24+·S23·Redmi 14C 4G·Pixel 9의 6종류 표시 설정을 사용했습니다. 기종별 설정은 30종류를 준비했지만, 이번에 실행한 것은 그중 6종류입니다.
이는 동일한 Android 14 에뮬레이터에 해상도와 검증용 근사 밀도를 적용한 것입니다. 제조사 고유의 OS나 글꼴, 카메라 홀을 재현하는 검증이나 30개 기종의 실기기 검증은 진행하지 않았습니다. Flutter 테스트는 Windows에서 실행했으며, Linux용 픽셀 일치 골든 비교도 이번에는 실행하지 않았습니다.
이번 기록은 표시 검증에 관한 것입니다. 화면 렌더링, 입력란 포커스, 스크롤 확인 결과로 오디오 재생이나 저장 처리의 성공까지 확인한 것은 아닙니다.
다음 UI 변경에서도 확인하고 싶은 것
이번 검증을 통해 표시 테스트에 남겨 둘 항목이 구체화되었습니다.
- 템포나 박 번호 등의 숫자는 중간에서 나누지 않는다.
- 오류 설명은 전체를 읽을 수 있게 한다.
- 글자를 키웠을 때나 입력 중에도 필요한 조작 버튼에 도달할 수 있게 한다.
글자 크기와 번역에 맞게 열 수를 바꾸거나 세로 배치와 스크롤을 사용하여 필요한 정보와 조작을 위한 영역을 확보했습니다.
자동 테스트로 조건을 반복 확인하고, 실제로 렌더링한 이미지에서 발견한 문제를 확인 항목에 추가합니다. 이 흐름을 남겨 다음에 UI를 변경할 때도 이번에 발견한 문제가 재발하지 않았는지 확인할 수 있게 되었습니다.