rtl-detect

Detects right-to-left languages and locale text direction in JavaScript.

Library
npm
v1.1.2
54stars
BSD 3-Clause License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
32/100Needs Attention
Development Activity0
Maintenance20
Community36
Maturity60
Momentum12

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
51/100Fair
Architecture60
Code Quality65
Innovation25
Learning Curve55

rtl-detect is a lightweight, dependency-free JavaScript utility for identifying whether a given locale or language code reads right-to-left. It exposes two functions - isRtlLang and getLangDir - that parse a locale string (e.g. ar-JO, en_US) and check the language portion against a maintained table of right-to-left BiDi scripts such as Arabic, Hebrew, Persian, Urdu, and Kurdish.

Originally built at Yahoo! and still maintained as a small standalone npm package, it is commonly pulled into i18n layers, CMS editors, and UI frameworks that need to flip layout direction (rtl vs ltr) based on the active locale, without pulling in a full internationalization framework.

What You Get

  • isRtlLang(locale) function returning true/false for whether a locale’s language is RTL
  • getLangDir(locale) function returning the literal ‘rtl’ or ‘ltr’ string for direct use in HTML dir attributes
  • A maintained table of 20 RTL BiDi language codes (Arabic, Hebrew, Persian, Urdu, Pashto, Kurdish, Yiddish, and others)
  • Locale string normalization that accepts both hyphen (ar-JO) and underscore (ar_JO) separators in any case

Common Use Cases

  • Setting the dir attribute on <html> or a root component based on the active locale
  • Conditionally loading RTL-specific CSS in a multi-language web app
  • Flipping layout direction in a CMS or page builder when an editor switches content language
  • Validating locale-driven text alignment in server-rendered i18n pipelines

Under The Hood

Architecture The package is a thin two-file module: index.js re-exports isRtlLang and getLangDir from lib/rtl-detect.js, which holds the entire implementation as a single self-referencing object literal (assigned to both a self closure variable and RtlDetectLib). Private helpers (_escapeRegExpPattern, _toLowerCase, _toUpperCase, _trim, _parseLocale) do locale normalization, and a frozen _BIDI_RTL_LANGS array is attached via Object.defineProperty with writable/configurable set to false. Data flow is a straight pipeline: a locale string is regex-parsed into {lang, countryCode}, the lang is lowercased and checked for membership in the RTL table, and the two public functions derive their boolean/string results from that single check. There is no dependency injection or plugin surface - because everything lives on one object literal, changing the core lookup mechanism would mean editing this one file directly rather than swapping an abstraction.

Tech Stack Plain ES5-style JavaScript with ‘use strict’, distributed as CommonJS (require/module.exports) with zero runtime dependencies. Tooling lives entirely in devDependencies: jest for tests, eslint for linting (run automatically via a pretest hook), and semantic-release plus its changelog/git plugins for automated versioned releases, paired with commitizen and cz-conventional-changelog for structured commit messages. A GitHub Actions workflow (referenced by the README’s build-status badge) runs CI on push. No bundler, transpiler, or TypeScript is used.

Code Quality A single test file (test/index.spec.js) exercises both public functions with jest’s describe/it, covering a wide edge-case matrix - undefined, null, empty string, whitespace, numeric strings, case variations, and both hyphen and underscore locale separators - though it tests only the public API surface, not the private helpers directly. ESLint enforces style before tests run via the pretest script. Naming is consistent (camelCase public API, underscore-prefixed private members) but there is no static type system, so malformed inputs are handled by runtime typeof checks rather than compile-time guarantees.

What Makes It Unique The library is not technically novel - locale-to-direction lookup is a solved problem covered by many i18n frameworks and even native Intl APIs - but its value is being an extremely small, dependency-free, single-purpose utility that answers exactly one question without pulling in a full internationalization stack.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search