null

Ищем пропавшие локали

При разработке приложений с использованием JSF в качестве фронт-энда возникла проблема отсутствия некоторых локалей в файлах сообщений. В частности, есть две конкретные проблемы: использование в .xhtml локалей, которые не объявлены в .properties и отсутствие некоторых локалей в ресурс-бандлах некоторых языков.

Сейчас мы попробуем решить эту проблему автоматизированно.

Напишем немножко кода, который будет искать файлы локализаций, выбирать из них локализации, искать .xhtml файлы, находить использование бина локализации и проверять, есть ли локали в тех самых файлах локализаций.

Найдём файлы локализации:

my @mfiles;
find( sub { push @mfiles, $File::Find::name unless -d }, 'src/main');
@mfiles = grep /Messages.*\.properties$/, @mfiles;

Теперь пооткрываем их и схороним данные:

for (@mfiles) {
  open(my $mfd, '<', $_) or die "Cannot open $_";
  for (<$mfd>) {
    $locales{$1} = 1 if /^(.*?)[\s]*=/;
  }
  close $mfd;
}

Далее стоит отыскать все .xhtml:

my @files;
find( sub { push @files, $File::Find::name unless -d }, 'src/main');
@files = grep /\.xhtml$/, @files;

Считаем их содержимое:

for my $fname (@files) {
  open(my $fd, '<', $fname) or warn "Cannot open $fname" and next;
  my $code = join '', <$fd>;
  close $fd;

Ну и проверим для каждого обращения к бину интернационализации, находится ли его параметр в файлах локализации:

  for ($code =~ /i18n\['(.+?)']/g) {
    print "$fname : <$_>\n" unless defined $locales{$_};
  }
}


Теперь попробуем решить проблему несоответствия содержимого файлов локалей разных языков. Для этого слегка исправим первую часть кода:

for my $file (@mfiles) {
  open(my $mfd, '<', $file) or die "Cannot open $file";
  for (<$mfd>) {
    ($locales{$1}, $locales_per_file{$file}->{$1}) = (1, 1) if /^(.*?)[\s]*=/;
  }
  close $mfd;
}

И добавим соответствующую неприглядную проверку:

for my $fname (keys %locales_per_file) {
  for my $locale (keys %{$locales_per_file{$fname}}) {
    for (keys %locales_per_file) {
      next if $_ eq $fname;
      print "$fname:$locale missing in $_\n" if 0 == grep {
        $_ eq $locale
      } keys %{$locales_per_file{$_}};
    }
  }
}

В результате получился следующий код, способный помочь при разработке JSF-приложений с большим объёмом локалей, которые надо синхронизировать между языками:

#!/usr/bin/perl
# Made by kk
#
# This script should be used to find messages, which haven't been written into
# message bundles. Just run it in the project root.

use File::Find;

use strict;
use warnings;

my %locales = ();
my %locales_per_file = ();

my @mfiles;
find( sub { push @mfiles, $File::Find::name unless -d }, 'src/main');
@mfiles = grep /Messages.*\.properties$/, @mfiles;
for my $file (@mfiles) {
  open(my $mfd, '<', $file) or die "Cannot open $file";
  for (<$mfd>) {
    ($locales{$1}, $locales_per_file{$file}->{$1}) = (1, 1) if /^(.*?)[\s]*=/;
  }
  close $mfd;
}

for my $fname (keys %locales_per_file) {
  for my $locale (keys %{$locales_per_file{$fname}}) {
    for (keys %locales_per_file) {
      next if $_ eq $fname;
      print "$fname:$locale missing in $_\n" if 0 == grep {
        $_ eq $locale
      } keys %{$locales_per_file{$_}};
    }
  }
}

my @files;
find( sub { push @files, $File::Find::name unless -d }, 'src/main');
@files = grep /\.xhtml$/, @files;

for my $fname (@files) {
  open(my $fd, '<', $fname) or warn "Cannot open $fname" and next;
  my $code = join '', <$fd>;
  close $fd;
  for ($code =~ /i18n\['(.+?)']/g) {
    print "$fname : <$_>\n" unless defined $locales{$_};
  }
}

 

Данный скрипт, конечно, можно развивать. К примеру, добавить проверку и для .java-файлов. Надеюсь, этот код кому-то сможет облегчить жизнь с синхронизацией локализаций в JSF-приложениях, на текущий момент он нашёл применение пока что лишь в одном проекте.

Назад