Skip to main content

car_license_plate 2.0.1 copy "car_license_plate: ^2.0.1" to clipboard
car_license_plate: ^2.0.1 copied to clipboard

Realistic, scalable licence plate widgets and validators for 20 countries: Iran, EU, UK, USA, Japan, China, India, Brazil and more.

car_license_plate #

Realistic licence plate widgets for Flutter, with a validator for each country. They're drawn as vectors to real millimetre specs, so they stay sharp and in proportion at any size.

pub package license: MIT

All plates

Features #

  • 28 designs across 20 countries and regions. Included are Iran, the EU (Germany, France, Italy, Spain, the Netherlands, plus a generic EU plate), the UK, four US states, Japan, China, South Korea, India, Indonesia, Brazil, Russia, Turkey, Ukraine, Saudi Arabia, Dubai and New South Wales.
  • True to spec. Each design uses the plate's real size and aspect ratio, its colours and bands (including the EU star circle and national codes), and its character heights and separators, taken from the regulations where available.
  • Validators. Each country can check, normalise, parse and format a registration, for example ab123cd → AB-123-CD. Persian and Arabic-Indic digits, Cyrillic letters and their Latin look-alikes are all accepted.
  • Responsive. Plates scale to any width or height, keep their aspect ratio and never overflow their parent.
  • Accessible. Each plate is one semantics node, and screen readers spell the registration out. System text scaling can't break the layout.
  • Works on every platform. The library is pure Dart with no dart:io and no platform channels. Fonts are bundled (OFL, subset, about 210 KB), so plates look the same everywhere.
  • RTL-safe. The plate layout doesn't mirror in Persian or Arabic apps.
  • Extensible. You can draw any other plate by extending PlateSpec.
  • Backward compatible. The 1.x Iranian CarLicensePlate widget, including its input mode, still works.

Install #

dependencies:
  car_license_plate: ^2.0.0

Quick start #

import 'package:car_license_plate/car_license_plate.dart';

LicensePlate(GermanPlate('B MW 1234', inspectionYear: 2026))
LicensePlate(const UkPlate('AB12 CDE'), width: 240)          // rear (yellow)
LicensePlate(UsPlate('123ABC1', style: UsPlateStyle.california))
LicensePlate(const JapanesePlate(
  region: '品川', classNumber: '330', hiragana: 'さ', serial: '1234',
))
LicensePlate(const IranPlate(
  twoDigits: '12', letter: 'ب', threeDigits: '345', provinceCode: '67',
))

Validate and format registrations:

FrenchPlate.format.isValid('AB-123-CD');   // true
FrenchPlate.format.format('ab123cd');      // 'AB-123-CD'
UkPlate.format.parse('AB12CDE')!['age'];   // '12'
IranPlate.parse('۱۲ ب ۳۴۵ ایران ۶۷');      // IranPlate(12, ب, 345, 67)
BrazilPlate.toMercosur('ABC-1234');        // 'ABC1C34'

If the country is only known at runtime (from a database, or from a camera reading a plate), look it up by code:

final plate = PlateRegistry.create('fr', 'ab123cd');   // a FrenchPlate
PlateRegistry.format('GB')!.isValid('AB12 CDE');       // true
PlateRegistry.detect('AB-123-CD');                     // ['FR', ...]

Supported plates #

Country Class Size (mm) Example Validator
Iran IranPlate, CarLicensePlate 520 × 110 12 ب 345 67 two digits, letter, three digits, province
Germany GermanPlate 520 × 110 B MW 1234 district, 1–2 letters, 1–4 digits, E/H, ≤ 8 characters
France FrenchPlate 520 × 110 AB-123-CD SIV, no I/O/U, no 000/SS/WW
Italy ItalianPlate 520 × 110 AB 123 CD no I/O/Q/U
Spain SpanishPlate 520 × 110 1234 BCD consonants only, no Ñ/Q
Netherlands DutchPlate 520 × 110 GBB-12-X sidecodes 1–14
Any EU country EuPlate 520 × 110 WI 12345 optional (pass your own)
United Kingdom UkPlate (front/rear, UK band, green flash) 520 × 111 AB12 CDE current, prefix and suffix series
USA UsPlate + UsPlateStyle (CA, TX, FL, NY, or your own) 305 × 152 123ABC1 per state
Japan JapanesePlate (private, commercial, kei) 330 × 165 品川 330 さ 12-34 office, class, hiragana, serial (・・12 style)
China ChinesePlate (blue, new energy, yellow) 440/480 × 140 京A·12345 31 provinces, no I/O; new-energy D/F series
South Korea KoreanPlate 520 × 110 123가 4567 private, commercial and rental syllables
India IndianPlate (private, commercial, EV, rental) 500 × 120 MH 12 AB 1234 state series and BH series
Indonesia IndonesianPlate 460 × 135 B 1234 XYZ plus MM.YY expiry
Brazil BrazilPlate (six categories) 400 × 130 ABC1D23 Mercosur, and converts old plates
Russia RussianPlate 520 × 112 А 123 ВС 77 the 12 allowed letters, region code
Turkey TurkishPlate 520 × 110 34 ABC 123 province 01–81
Ukraine UkrainianPlate 520 × 112 АА 1234 ВВ Cyrillic or Latin look-alikes
Saudi Arabia SaudiPlate 520 × 110 1234 ABJ the 17 letters; the Arabic row is derived
UAE (Dubai) DubaiPlate 520 × 110 A 12345 code plus up to 5 digits
Australia (NSW) NswPlate 372 × 134 AB·12·CD 2004+ series

Every design is also available as a high-resolution screenshot, including a dark-background gallery.

Size, shadow and theme #

LicensePlate(plate)               // available width, at most 360 px
LicensePlate(plate, width: 200)   // exact width; height follows the aspect ratio
LicensePlate(plate, height: 48)   // exact height
LicensePlate(plate, elevation: 4) // soft shadow
LicensePlate(plate, onTap: () {}) // tappable (announced as a button)

LicensePlateTheme(                // defaults for every plate below
  width: 240,
  elevation: 2,
  child: ...,
)

Plates always keep their real colours: a white plate stays white in dark mode, as it does on a car. The look of a plate is set by its parameters, for example:

  • UkPlate(rear: false, band: UkBand.green)
  • JapanesePlate(type: JapanesePlateType.keiPrivate)
  • IndianPlate(category: IndianPlateCategory.electric)
  • BrazilPlate(category: BrazilPlateCategory.commercial)
  • ChinesePlate(type: ChinesePlateType.newEnergy)
  • GermanPlate(inspectionYear: 2027, front: true)
  • FrenchPlate(department: '13')

For any other US state or Canadian province, define a UsPlateStyle with your own name, slogan and colours.

Iranian plates and input (1.x API) #

The original widget still works, including the input mode:

CarLicensePlate(
  isInputType: true,
  twoNumberSection: two,
  alphabetSection: letter,
  threeNumberSection: three,
  cityNumber: province,
  usePersianNumbers: true,
  onTwoNumberChanged: (v) => setState(() => two = v),     // always 0-9 digits
  onThreeNumberChanged: (v) => setState(() => three = v),
  onCityNumberChanged: (v) => setState(() => province = v),
  onAlphabetTap: () async {
    final l = await showIranPlateLetterPicker(context);
    if (l != null) setState(() => letter = l);
  },
)
  • IranPlate.letters lists every plate letter, and IranPlate.privateLetters lists the private-car series.
  • ژ with disability: true draws the wheelchair symbol.

Accessibility #

  • Each LicensePlate is announced as one item, for example "Germany licence plate B MW 1234", with the registration marked to be spelled out character by character.
  • Use semanticLabel: to translate the label.
  • The plate ignores the system text scale factor so its layout stays correct. It still scales with the size you give it.

Draw your own plate #

class FreedoniaPlate extends PlateSpec {
  const FreedoniaPlate(this.registration);
  @override final String registration;
  @override String get countryCode => 'XF';
  @override String get countryName => 'Freedonia';
  @override Size get size => const Size(520, 110);           // millimetres
  @override PlateFormat get registrationFormat => PlateFormat(
        countryCode: 'XF', name: 'Freedonia',
        pattern: r'^[A-Z]{2} ?\d{4}$', example: 'AB 1234');

  @override
  Widget buildFace(BuildContext context) => PlateSurface(
        size: size, borderWidth: 2,
        children: [
          const PlateBox(left: 0, top: 0, width: 44, height: 110,
              child: EuBand(code: 'XF', stars: false)),
          PlateBox(left: 50, top: 0, width: 460, height: 110,
              child: PlateText(registration, height: 75,
                  color: PlateColors.black)),
        ],
      );
}

buildFace is laid out at the plate's size in millimetres; LicensePlate scales it. Helpers you can use:

  • PlateText draws text by real character height and condenses it to fit, as plate typefaces do.
  • PlateRow, PlateSegment, PlateDot and PlateDash lay out character groups and separators.
  • EuBand, StripeFlag and UnionFlag draw bands and flags.

Migrating from 1.x #

2.0 is a major release because the Iranian plate now draws correctly, and that changes what existing apps see:

  • Section order. The plate reads left to right as on real plates: twoNumberSection, letter, threeNumberSection, then cityNumber under «ایران». 1.x drew the numbers in reverse order. If you swapped your arguments to compensate, swap them back.
  • twoNumberSection takes 2 digits, not 3, in input mode.
  • Dark mode. The plate stays white with black characters instead of switching to a white-on-white image.
  • Input callbacks always receive Latin digits (0-9), even when typed on a Persian or Arabic keyboard. Non-digits are ignored.
  • Leading zeros are kept (05 no longer becomes 5).
  • textSize is now relative to the 1.x default for the same width, and is clamped so text can't leave its section.
  • The intl dependency and the PNG assets have been removed. Plates are drawn in code.

Platform support #

Platform Status
Web Example app built with flutter build web
Windows (tests) 79 package tests and 1 example test, including golden and pixel checks, run with real fonts
Android, iOS, macOS, Linux, Windows desktop Supported but not built for this release

The last row is supported because the library is pure Dart: no dart:io, no plugins. Those targets haven't been built or run on a device for this release.

Accuracy and fonts #

Dimensions, colours and formats come from the regulations where they're public. These include EU Regulation 2411/98, the German FZV, the French SIV order, the Spanish RGV, Brazil's CONTRAN 780/2019, Russia's GOST R 50577 and the UK's BS AU 145e. Elsewhere they come from well-sourced secondary references.

National emblems, seals and holograms are simplified. Official typefaces (FE-Schrift, Charles Wright and others) aren't freely licensed, so the plates use similar open fonts. These renderings are for apps and illustrations, not for making real plates.

The bundled fonts are subsets of Barlow Condensed, Vazirmatn, Noto Sans SC, Noto Sans JP and Noto Sans KR. All are under the SIL Open Font License 1.1, and the licence texts are in fonts/. Characters missing from a subset fall back to the system font. To use your own licensed plate font, extend PlateSpec and use PlateFont.latin.withFamily('YourFont').

License #

MIT

7
likes
160
points
213
downloads
screenshot

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Realistic, scalable licence plate widgets and validators for 20 countries: Iran, EU, UK, USA, Japan, China, India, Brazil and more.

Repository (GitHub)
View/report issues

Topics

#license-plate #number-plate #widget #validation #persian

License

MIT (license)

Dependencies

flutter

More

Packages that depend on car_license_plate