Right-to-left support

Right-to-left support (RTL 지원)

아랍어, 페르시아어, 히브리어 같은 RTL(right-to-left) 언어를 지원하기 위해 Material UI에서 오른쪽에서 왼쪽으로 쓰는 텍스트를 구현하는 방법을 배워봐요.

출처: 문서

본문

Setup (설정)

이 가이드에서는 Material UI의 텍스트 기반 컴포넌트 방향을 RTL 언어를 지원하도록 바꾸는 데 필요한 세 가지 단계를 설명해요. 아래 데모에서 볼 수 있듯이요:

import { createTheme, ThemeProvider, Theme } from '@mui/material/styles';
import TextField from '@mui/material/TextField';
import rtlPlugin from '@mui/stylis-plugin-rtl';
import { prefixer } from 'stylis';
import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';

// Consuming the outer theme is only required with coexisting themes, like in this documentation.
// If your app/website doesn't deal with this, you can have just:
// const theme = createTheme({ direction: 'rtl' })
const theme = (outerTheme: Theme) =>
  createTheme({
    direction: 'rtl',
    palette: {
      mode: outerTheme.palette.mode,
    },
  });

const cacheRtl = createCache({
  key: 'muirtl',
  stylisPlugins: [prefixer, rtlPlugin],
});

export default function RtlDemo() {
  return (
    <CacheProvider value={cacheRtl}>
      <ThemeProvider theme={theme}>
        <div dir="rtl">
          <TextField
            label="ملصق"
            placeholder="العنصر النائب"
            helperText="هذا نص مساعد"
            variant="outlined"
          />
        </div>
      </ThemeProvider>
    </CacheProvider>
  );
}

1. Set the HTML direction (HTML 방향 설정)

텍스트 방향은 사용 사례에 따라 전역(앱 전체)으로 설정하거나 로컬(개별 컴포넌트만)로 설정할 수 있어요.

Globally (전역으로)

앱의 루트 <html>에 dir="rtl"을 추가해서 전체 텍스트 방향을 설정해요:

<html dir="rtl"></html>

루트 <html> 요소에 직접 dir 속성을 설정할 수 없다면, 페이지가 렌더링되기 전에 JavaScript API를 사용하는 방법이 있어요:

document.documentElement.setAttribute('dir', 'rtl');

Locally (로컬로)

텍스트 방향의 범위를 특정 요소와 그 자식들로 제한해야 한다면, 다른 HTML 요소나 React 컴포넌트에 dir="rtl" 속성을 추가하면 돼요.

:::warning React 포털(portal)을 사용하는 컴포넌트(예: Dialog)는 실제로 부모 DOM 트리 밖에 렌더링되기 때문에 부모로부터 dir 속성을 상속받지 않아요.

이 컴포넌트들이 전역으로 오른쪽에서 왼쪽(RTL)으로 정의되어 있지 않다면, 이런 컴포넌트에 dir 속성을 직접 적용해야 해요:

<Box dir="rtl">
  <Dialog /> // ❌ this Dialog will still be left-to-right (the default)
</Box>
<Box dir="rtl">
  <Dialog dir="rtl" /> // ✅ this Dialog will be right-to-left as intended
</Box>

:::

2. Set the theme direction (테마 방향 설정)

createTheme() API를 사용해서 테마 방향을 'rtl'로 설정해요:

import { createTheme } from '@mui/material/styles';

const theme = createTheme({
  direction: 'rtl',
});

3. Configure RTL style plugin (RTL 스타일 플러그인 구성)

아래 명령 중 하나를 사용해서 @mui/stylis-plugin-rtl을 설치해요:

npm install stylis @mui/stylis-plugin-rtl
pnpm add stylis @mui/stylis-plugin-rtl
yarn add stylis @mui/stylis-plugin-rtl

With Emotion (Emotion 사용 시)

Emotion을 사용하고 있다면, CacheProvider를 사용해서 @mui/stylis-plugin-rtl의 rtlPlugin을 사용하는 새로운 캐시 인스턴스를 만들고, 이를 애플리케이션 트리 맨 위에 추가해요:

import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';
import { prefixer } from 'stylis';
import rtlPlugin from '@mui/stylis-plugin-rtl';

// Create rtl cache
const rtlCache = createCache({
  key: 'muirtl',
  stylisPlugins: [prefixer, rtlPlugin],
});

function Rtl(props) {
  return <CacheProvider value={rtlCache}>{props.children}</CacheProvider>;
}

With styled-components (styled-components 사용 시)

styled-components를 사용하고 있다면, StyleSheetManager를 사용해서 stylisPlugins 속성에 rtlPlugin을 제공해요:

import { StyleSheetManager } from 'styled-components';
import rtlPlugin from '@mui/stylis-plugin-rtl';

function Rtl(props) {
  return (
    <StyleSheetManager stylisPlugins={[rtlPlugin]}>
      {props.children}
    </StyleSheetManager>
  );
}

Opting out of RTL locally (로컬에서 RTL 제외하기)

특정 컴포넌트에서 RTL을 끄려면 템플릿 리터럴(template literal) 문법을 사용하고 /* @noflip */ 지시문을 추가해요:

const LeftToRightTextInRtlApp = styled('div')`
  /* @noflip */
  text-align: left;
`;
import * as React from 'react';
import { prefixer } from 'stylis';
import rtlPlugin from '@mui/stylis-plugin-rtl';
import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';
import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import FormControlLabel from '@mui/material/FormControlLabel';
import Switch from '@mui/material/Switch';

const Normal = styled('div')`
  text-align: left;
`;

const Noflip = styled('div')`
  /* @noflip */
  text-align: left;
`;

const rtlCache = createCache({
  key: 'muirtl',
  stylisPlugins: [prefixer, rtlPlugin],
});

const ltrCache = createCache({
  key: 'mui',
});

export default function RtlOptOut() {
  const [rtl, setRtl] = React.useState(false);

  const handleChange = () => {
    setRtl(!rtl);
  };

  return (
    <Box sx={{ width: '100%', display: 'flex' }}>
      <FormControlLabel
        control={<Switch onChange={handleChange} />}
        label="Toggle RTL"
      />
      <CacheProvider value={rtl ? rtlCache : ltrCache}>
        <Box sx={{ flexGrow: 1, mx: 2 }} dir={rtl ? 'rtl' : undefined}>
          <Normal>RTL normal behavior</Normal>
          <Noflip>RTL noflip</Noflip>
        </Box>
      </CacheProvider>
    </Box>
  );
}

더 알아보기 (Learn more)