При разработке приложений с использованием 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-приложениях, на текущий момент он нашёл применение пока что лишь в одном проекте.