add og firmware
This commit is contained in:
parent
f3c8b13122
commit
b2495bdfac
186 changed files with 119377 additions and 1 deletions
66
lang/config.sh
Normal file
66
lang/config.sh
Normal file
|
@ -0,0 +1,66 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# config.sh - multi-language support configuration script
|
||||
# Definition of absolute paths etc.
|
||||
# This file is 'included' in all scripts.
|
||||
#
|
||||
# Arduino main folder:
|
||||
if [ -z "$ARDUINO" ]; then
|
||||
export ARDUINO=C:/arduino-1.8.5
|
||||
fi
|
||||
#
|
||||
# Arduino builder:
|
||||
export BUILDER=$ARDUINO/arduino-builder
|
||||
#
|
||||
# AVR gcc tools:
|
||||
export OBJCOPY=$ARDUINO/hardware/tools/avr/bin/avr-objcopy
|
||||
export OBJDUMP=$ARDUINO/hardware/tools/avr/bin/avr-objdump
|
||||
#
|
||||
# Output folder:
|
||||
export OUTDIR="../../Prusa-Firmware-build"
|
||||
#
|
||||
# Objects folder:
|
||||
export OBJDIR="$OUTDIR/sketch"
|
||||
#
|
||||
# Generated elf file:
|
||||
export INOELF="$OUTDIR/Firmware.ino.elf"
|
||||
#
|
||||
# Generated hex file:
|
||||
export INOHEX="$OUTDIR/Firmware.ino.hex"
|
||||
|
||||
|
||||
echo "config.sh started" >&2
|
||||
|
||||
_err=0
|
||||
|
||||
echo -n " Arduino main folder: " >&2
|
||||
if [ -e $ARDUINO ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=1; fi
|
||||
|
||||
echo -n " Arduino builder: " >&2
|
||||
if [ -e $BUILDER ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=2; fi
|
||||
|
||||
echo " AVR gcc tools:" >&2
|
||||
echo -n " objcopy " >&2
|
||||
if [ -e $OBJCOPY ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=3; fi
|
||||
echo -n " objdump " >&2
|
||||
if [ -e $OBJDUMP ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=4; fi
|
||||
|
||||
echo -n " Output folder: " >&2
|
||||
if [ -e $OUTDIR ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=5; fi
|
||||
|
||||
echo -n " Objects folder: " >&2
|
||||
if [ -e $OBJDIR ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=6; fi
|
||||
|
||||
echo -n " Generated elf file: " >&2
|
||||
if [ -e $INOELF ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=7; fi
|
||||
|
||||
echo -n " Generated hex file: " >&2
|
||||
if [ -e $INOHEX ]; then echo 'OK' >&2; else echo 'NG!' >&2; _err=8; fi
|
||||
|
||||
if [ $_err -eq 0 ]; then
|
||||
echo "config.sh finished with success" >&2
|
||||
export CONFIG_OK=1
|
||||
else
|
||||
echo "config.sh finished with errors!" >&2
|
||||
export CONFIG_OK=0
|
||||
fi
|
186
lang/fw-build.sh
Normal file
186
lang/fw-build.sh
Normal file
|
@ -0,0 +1,186 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# postbuild.sh - multi-language support script
|
||||
# Generate binary with secondary language.
|
||||
#
|
||||
# Input files:
|
||||
# $OUTDIR/Firmware.ino.elf
|
||||
# $OUTDIR/sketch/*.o (all object files)
|
||||
#
|
||||
# Output files:
|
||||
# text.sym
|
||||
# $PROGMEM.sym (progmem1.sym)
|
||||
# $PROGMEM.lss (...)
|
||||
# $PROGMEM.hex
|
||||
# $PROGMEM.chr
|
||||
# $PROGMEM.var
|
||||
# $PROGMEM.txt
|
||||
# textaddr.txt
|
||||
#
|
||||
#
|
||||
# Config:
|
||||
if [ -z "$CONFIG_OK" ]; then eval "$(cat config.sh)"; fi
|
||||
if [ -z "$CONFIG_OK" ] | [ $CONFIG_OK -eq 0 ]; then echo 'Config NG!' >&2; exit 1; fi
|
||||
#
|
||||
# Selected language:
|
||||
LNG=$1
|
||||
#if [ -z "$LNG" ]; then LNG='cz'; fi
|
||||
#
|
||||
# Params:
|
||||
IGNORE_MISSING_TEXT=1
|
||||
|
||||
|
||||
finish()
|
||||
{
|
||||
echo
|
||||
if [ "$1" = "0" ]; then
|
||||
echo "postbuild.sh finished with success" >&2
|
||||
else
|
||||
echo "postbuild.sh finished with errors!" >&2
|
||||
fi
|
||||
case "$-" in
|
||||
*i*) echo "press enter key"; read ;;
|
||||
esac
|
||||
exit $1
|
||||
}
|
||||
|
||||
echo "postbuild.sh started" >&2
|
||||
|
||||
#check input files
|
||||
echo " checking files:" >&2
|
||||
if [ ! -e $OUTDIR ]; then echo " folder '$OUTDIR' not found!" >&2; finish 1; fi
|
||||
echo " folder OK" >&2
|
||||
if [ ! -e $INOELF ]; then echo " elf file '$INOELF' not found!" >&2; finish 1; fi
|
||||
echo " elf OK" >&2
|
||||
if ! ls $OBJDIR/*.o >/dev/null 2>&1; then echo " no object files in '$OBJDIR/'!" >&2; finish 1; fi
|
||||
echo " objects OK" >&2
|
||||
|
||||
#run progmem.sh - examine content of progmem1
|
||||
echo -n " running progmem.sh..." >&2
|
||||
./progmem.sh 1 2>progmem.out
|
||||
if [ $? -ne 0 ]; then echo "NG! - check progmem.out file" >&2; finish 1; fi
|
||||
echo "OK" >&2
|
||||
|
||||
#run textaddr.sh - map progmem addreses to text identifiers
|
||||
echo -n " running textaddr.sh..." >&2
|
||||
./textaddr.sh 2>textaddr.out
|
||||
if [ $? -ne 0 ]; then echo "NG! - check progmem.out file" >&2; finish 1; fi
|
||||
echo "OK" >&2
|
||||
|
||||
#check for messages declared in progmem1, but not found in lang_en.txt
|
||||
echo -n " checking textaddr.txt..." >&2
|
||||
cat textaddr.txt | grep "^TEXT NF" | sed "s/[^\"]*\"//;s/\"$//" >not_used.txt
|
||||
cat textaddr.txt | grep "^ADDR NF" | sed "s/[^\"]*\"//;s/\"$//" >not_tran.txt
|
||||
if cat textaddr.txt | grep "^ADDR NF" >/dev/null; then
|
||||
echo "NG! - some texts not found in lang_en.txt!"
|
||||
if [ $IGNORE_MISSING_TEXT -eq 0 ]; then
|
||||
finish 1
|
||||
else
|
||||
echo " missing text ignored!" >&2
|
||||
fi
|
||||
else
|
||||
echo "OK" >&2
|
||||
fi
|
||||
|
||||
#extract binary file
|
||||
echo -n " extracting binary..." >&2
|
||||
$OBJCOPY -I ihex -O binary $INOHEX ./firmware.bin
|
||||
echo "OK" >&2
|
||||
|
||||
#update binary file
|
||||
echo " updating binary:" >&2
|
||||
|
||||
#update progmem1 id entries in binary file
|
||||
echo -n " primary language ids..." >&2
|
||||
cat textaddr.txt | grep "^ADDR OK" | cut -f3- -d' ' | sed "s/^0000/0x/" |\
|
||||
awk '{ id = $2 - 1; hi = int(id / 256); lo = int(id - 256 * hi); printf("%d \\\\x%02x\\\\x%02x\n", strtonum($1), lo, hi); }' |\
|
||||
while read addr data; do
|
||||
/bin/echo -n -e $data | dd of=./firmware.bin bs=1 count=2 seek=$addr conv=notrunc oflag=nonblock 2>/dev/null
|
||||
done
|
||||
echo "OK" >&2
|
||||
|
||||
#update primary language signature in binary file
|
||||
echo -n " primary language signature..." >&2
|
||||
if [ -e lang_en.bin ]; then
|
||||
#find symbol _PRI_LANG_SIGNATURE in section '.text'
|
||||
pri_lang=$(cat text.sym | grep -E "\b_PRI_LANG_SIGNATURE\b")
|
||||
if [ -z "$pri_lang" ]; then echo "NG!\n symbol _PRI_LANG_SIGNATURE not found!" >&2; finish 1; fi
|
||||
#get pri_lang address
|
||||
pri_lang_addr='0x'$(echo $pri_lang | cut -f1 -d' ')
|
||||
#read header from primary language binary file
|
||||
header=$(dd if=lang_en.bin bs=1 count=16 2>/dev/null | xxd | cut -c11-49 | sed 's/\([0-9a-f][0-9a-f]\)[\ ]*/\1 /g')
|
||||
#read checksum and count data as 4 byte signature
|
||||
chscnt=$(echo $header | cut -c18-29 | sed "s/ /\\\\x/g")
|
||||
/bin/echo -e -n "$chscnt" |\
|
||||
dd of=firmware.bin bs=1 count=4 seek=$(($pri_lang_addr)) conv=notrunc 2>/dev/null
|
||||
echo "OK" >&2
|
||||
else
|
||||
echo "NG! - file lang_en.bin not found!" >&2;
|
||||
finish 1
|
||||
fi
|
||||
|
||||
#convert bin to hex
|
||||
echo -n " converting to hex..." >&2
|
||||
$OBJCOPY -I binary -O ihex ./firmware.bin ./firmware.hex
|
||||
echo "OK" >&2
|
||||
|
||||
#update _SEC_LANG in binary file if language is selected
|
||||
echo -n " secondary language data..." >&2
|
||||
if [ ! -z "$LNG" ]; then
|
||||
./update_lang.sh $LNG 2>./update_lang.out
|
||||
if [ $? -ne 0 ]; then echo "NG! - check update_lang.out file" >&2; finish 1; fi
|
||||
echo "OK" >&2
|
||||
finish 0
|
||||
else
|
||||
echo "Updating languages:" >&2
|
||||
if [ -e lang_cz.bin ]; then
|
||||
echo -n " Czech : " >&2
|
||||
./update_lang.sh cz 2>./update_lang_cz.out 1>/dev/null
|
||||
if [ $? -eq 0 ]; then echo 'OK' >&2; else echo 'NG!' >&2; finish 1; fi
|
||||
fi
|
||||
if [ -e lang_de.bin ]; then
|
||||
echo -n " German : " >&2
|
||||
./update_lang.sh de 2>./update_lang_de.out 1>/dev/null
|
||||
if [ $? -eq 0 ]; then echo 'OK' >&2; else echo 'NG!' >&2; finish 1; fi
|
||||
fi
|
||||
if [ -e lang_it.bin ]; then
|
||||
echo -n " Italian: " >&2
|
||||
./update_lang.sh it 2>./update_lang_it.out 1>/dev/null
|
||||
if [ $? -eq 0 ]; then echo 'OK' >&2; else echo 'NG!' >&2; finish 1; fi
|
||||
fi
|
||||
if [ -e lang_es.bin ]; then
|
||||
echo -n " Spanish: " >&2
|
||||
./update_lang.sh es 2>./update_lang_es.out 1>/dev/null
|
||||
if [ $? -eq 0 ]; then echo 'OK' >&2; else echo 'NG!' >&2; finish 1; fi
|
||||
fi
|
||||
if [ -e lang_fr.bin ]; then
|
||||
echo -n " French : " >&2
|
||||
./update_lang.sh fr 2>./update_lang_fr.out 1>/dev/null
|
||||
if [ $? -eq 0 ]; then echo 'OK' >&2; else echo 'NG!' >&2; finish 1; fi
|
||||
fi
|
||||
if [ -e lang_pl.bin ]; then
|
||||
echo -n " Polish : " >&2
|
||||
./update_lang.sh pl 2>./update_lang_pl.out 1>/dev/null
|
||||
if [ $? -eq 0 ]; then echo 'OK' >&2; else echo 'NG!' >&2; finish 1; fi
|
||||
fi
|
||||
# echo "skipped" >&2
|
||||
fi
|
||||
|
||||
#create binary file with all languages
|
||||
rm -f lang.bin
|
||||
if [ -e lang_cz.bin ]; then cat lang_cz.bin >> lang.bin; fi
|
||||
if [ -e lang_de.bin ]; then cat lang_de.bin >> lang.bin; fi
|
||||
if [ -e lang_es.bin ]; then cat lang_es.bin >> lang.bin; fi
|
||||
if [ -e lang_fr.bin ]; then cat lang_fr.bin >> lang.bin; fi
|
||||
if [ -e lang_it.bin ]; then cat lang_it.bin >> lang.bin; fi
|
||||
if [ -e lang_pl.bin ]; then cat lang_pl.bin >> lang.bin; fi
|
||||
|
||||
#convert lang.bin to lang.hex
|
||||
echo -n " converting to hex..." >&2
|
||||
$OBJCOPY -I binary -O ihex ./lang.bin ./lang.hex
|
||||
echo "OK" >&2
|
||||
|
||||
#append languages to hex file
|
||||
cat ./lang.hex >> firmware.hex
|
||||
|
||||
finish 0
|
63
lang/fw-clean.sh
Normal file
63
lang/fw-clean.sh
Normal file
|
@ -0,0 +1,63 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# fw-clean.sh - multi-language support script
|
||||
# Remove all firmware output files from lang folder.
|
||||
#
|
||||
|
||||
result=0
|
||||
|
||||
rm_if_exists()
|
||||
{
|
||||
if [ -e $1 ]; then
|
||||
echo -n " removing '$1'..." >&2
|
||||
if rm $1; then
|
||||
echo "OK" >&2
|
||||
else
|
||||
echo "NG!" >&2
|
||||
result=1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
echo "fw-clean.sh started" >&2
|
||||
|
||||
rm_if_exists text.sym
|
||||
rm_if_exists progmem1.sym
|
||||
rm_if_exists progmem1.lss
|
||||
rm_if_exists progmem1.hex
|
||||
rm_if_exists progmem1.chr
|
||||
rm_if_exists progmem1.var
|
||||
rm_if_exists progmem1.txt
|
||||
rm_if_exists textaddr.txt
|
||||
rm_if_exists firmware.bin
|
||||
rm_if_exists firmware.hex
|
||||
rm_if_exists firmware_cz.hex
|
||||
rm_if_exists firmware_de.hex
|
||||
rm_if_exists firmware_es.hex
|
||||
rm_if_exists firmware_fr.hex
|
||||
rm_if_exists firmware_it.hex
|
||||
rm_if_exists firmware_pl.hex
|
||||
rm_if_exists progmem.out
|
||||
rm_if_exists textaddr.out
|
||||
rm_if_exists update_lang.out
|
||||
rm_if_exists update_lang_cz.out
|
||||
rm_if_exists update_lang_de.out
|
||||
rm_if_exists update_lang_es.out
|
||||
rm_if_exists update_lang_fr.out
|
||||
rm_if_exists update_lang_it.out
|
||||
rm_if_exists update_lang_pl.out
|
||||
rm_if_exists lang.bin
|
||||
rm_if_exists lang.hex
|
||||
|
||||
echo -n "fw-clean.sh finished" >&2
|
||||
if [ $result -eq 0 ]; then
|
||||
echo " with success" >&2
|
||||
else
|
||||
echo " with errors!" >&2
|
||||
fi
|
||||
|
||||
case "$-" in
|
||||
*i*) echo "press enter key"; read ;;
|
||||
esac
|
||||
|
||||
exit $result
|
10
lang/iso639-1.txt
Normal file
10
lang/iso639-1.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
#language codes ISO639-1
|
||||
# iso english localized
|
||||
#-----------------------
|
||||
# en English English
|
||||
# de German Deutsch
|
||||
# cs Czech Cestina
|
||||
# es Spanish Espanol
|
||||
# fr French Francais
|
||||
# it Italian Italiano
|
||||
# pl Polish Polski
|
73
lang/lang-add.sh
Normal file
73
lang/lang-add.sh
Normal file
|
@ -0,0 +1,73 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# lang-add.sh - multi-language support script
|
||||
# add new texts from list (lang_add.txt) to all dictionary files
|
||||
#
|
||||
# Input files:
|
||||
# lang_add.txt
|
||||
# Updated files:
|
||||
# lang_en.txt and all lang_en_xx.txt
|
||||
#
|
||||
|
||||
|
||||
# insert single text to english dictionary
|
||||
# $1 - text to insert
|
||||
insert_en()
|
||||
{
|
||||
#replace '[' and ']' in string with '\[' and '\]'
|
||||
str=$(echo "$1" | sed "s/\[/\\\[/g;s/\]/\\\]/g")
|
||||
# extract english texts, merge new text, grep line number
|
||||
ln=$((cat lang_en.txt; echo "$1") | sed "/^$/d;/^#/d" | sort | grep -n "$str" | sed "s/:.*//")
|
||||
# calculate position for insertion
|
||||
ln=$((3*(ln-2)+1))
|
||||
# insert new text
|
||||
sed -i "$ln"'i\\' lang_en.txt
|
||||
sed -i "$ln"'i\'"$1"'\' lang_en.txt
|
||||
sed -i "$ln"'i\#\' lang_en.txt
|
||||
}
|
||||
|
||||
# insert single text to translated dictionary
|
||||
# $1 - text to insert
|
||||
# $2 - sufix
|
||||
insert_xx()
|
||||
{
|
||||
#replace '[' and ']' in string with '\[' and '\]'
|
||||
str=$(echo "$1" | sed "s/\[/\\\[/g;s/\]/\\\]/g")
|
||||
# extract english texts, merge new text, grep line number
|
||||
ln=$((cat lang_en_$2.txt; echo "$1") | sed "/^$/d;/^#/d" | sed -n 'p;n' | sort | grep -n "$str" | sed "s/:.*//")
|
||||
# calculate position for insertion
|
||||
ln=$((4*(ln-2)+1))
|
||||
# insert new text
|
||||
sed -i "$ln"'i\\' lang_en_$2.txt
|
||||
sed -i "$ln"'i\"\x00"\' lang_en_$2.txt
|
||||
sed -i "$ln"'i\'"$1"'\' lang_en_$2.txt
|
||||
sed -i "$ln"'i\#\' lang_en_$2.txt
|
||||
}
|
||||
|
||||
# check if input file exists
|
||||
if ! [ -e lang_add.txt ]; then
|
||||
echo "file lang_add.txt not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat lang_add.txt | sed 's/^/"/;s/$/"/' | while read new_s; do
|
||||
if grep "$new_s" lang_en.txt >/dev/null; then
|
||||
echo "text already exist:"
|
||||
echo "$new_s"
|
||||
echo
|
||||
else
|
||||
echo "adding text:"
|
||||
echo "$new_s"
|
||||
echo
|
||||
insert_en "$new_s"
|
||||
insert_xx "$new_s" 'cz'
|
||||
insert_xx "$new_s" 'de'
|
||||
insert_xx "$new_s" 'es'
|
||||
insert_xx "$new_s" 'fr'
|
||||
insert_xx "$new_s" 'it'
|
||||
insert_xx "$new_s" 'pl'
|
||||
fi
|
||||
done
|
||||
|
||||
read x
|
||||
exit 0
|
142
lang/lang-build.sh
Normal file
142
lang/lang-build.sh
Normal file
|
@ -0,0 +1,142 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# lang-build.sh - multi-language support script
|
||||
# generate lang_xx.bin (language binary file)
|
||||
#
|
||||
# Input files:
|
||||
# lang_en.txt or lang_en_xx.txt
|
||||
#
|
||||
# Output files:
|
||||
# lang_xx.bin
|
||||
#
|
||||
# Temporary files:
|
||||
# lang_xx.tmp
|
||||
# lang_xx.dat
|
||||
#
|
||||
|
||||
#awk code to format ui16 variables for dd
|
||||
awk_ui16='{ h=int($1/256); printf("\\x%02x\\x%02x\n", int($1-256*h), h); }'
|
||||
|
||||
#startup message
|
||||
echo "lang-build.sh started" >&2
|
||||
|
||||
#exiting function
|
||||
finish()
|
||||
{
|
||||
if [ $1 -eq 0 ]; then
|
||||
echo "lang-build.sh finished with success" >&2
|
||||
else
|
||||
echo "lang-build.sh finished with errors!" >&2
|
||||
fi
|
||||
exit $1
|
||||
}
|
||||
|
||||
#returns hexadecial data for lang code
|
||||
lang_code_hex_data()
|
||||
# $1 - language code ('en', 'cz'...)
|
||||
{
|
||||
case "$1" in
|
||||
*en*) echo '\x6e\x65' ;;
|
||||
*cz*) echo '\x73\x63' ;;
|
||||
*de*) echo '\x65\x64' ;;
|
||||
*es*) echo '\x73\x65' ;;
|
||||
*fr*) echo '\x72\x66' ;;
|
||||
*it*) echo '\x74\x69' ;;
|
||||
*pl*) echo '\x6c\x70' ;;
|
||||
esac
|
||||
echo '??'
|
||||
}
|
||||
|
||||
write_header()
|
||||
# $1 - lang
|
||||
# $2 - size
|
||||
# $3 - count
|
||||
# $4 - checksum
|
||||
# $5 - signature
|
||||
{
|
||||
/bin/echo -n -e "\xa5\x5a\xb4\x4b" |\
|
||||
dd of=lang_$1.bin bs=1 count=4 seek=0 conv=notrunc 2>/dev/null
|
||||
/bin/echo -n -e $(echo -n "$(($2))" | awk "$awk_ui16") |\
|
||||
dd of=lang_$1.bin bs=1 count=2 seek=4 conv=notrunc 2>/dev/null
|
||||
/bin/echo -n -e $(echo -n "$(($3))" | awk "$awk_ui16") |\
|
||||
dd of=lang_$1.bin bs=1 count=2 seek=6 conv=notrunc 2>/dev/null
|
||||
/bin/echo -n -e $(echo -n "$(($4))" | awk "$awk_ui16") |\
|
||||
dd of=lang_$1.bin bs=1 count=2 seek=8 conv=notrunc 2>/dev/null
|
||||
/bin/echo -n -e "$(lang_code_hex_data $1)" |\
|
||||
dd of=lang_$1.bin bs=1 count=2 seek=10 conv=notrunc 2>/dev/null
|
||||
sig_h=$(($5 / 65536))
|
||||
/bin/echo -n -e $(echo -n "$sig_h" | awk "$awk_ui16") |\
|
||||
dd of=lang_$1.bin bs=1 count=2 seek=14 conv=notrunc 2>/dev/null
|
||||
sig_l=$(($5 - $sig_h * 65536))
|
||||
/bin/echo -n -e $(echo -n "$sig_l" | awk "$awk_ui16") |\
|
||||
dd of=lang_$1.bin bs=1 count=2 seek=12 conv=notrunc 2>/dev/null
|
||||
}
|
||||
|
||||
generate_binary()
|
||||
# $1 - language code ('en', 'cz'...)
|
||||
{
|
||||
echo "lang="$1 >&2
|
||||
#remove output and temporary files
|
||||
rm -f lang_$1.bin
|
||||
rm -f lang_$1.tmp
|
||||
rm -f lang_$1.dat
|
||||
LNG=$1
|
||||
#check lang dictionary
|
||||
/usr/bin/env python lang-check.py $1 --no-warning
|
||||
#create lang_xx.tmp - different processing for 'en' language
|
||||
if [ "$1" = "en" ]; then
|
||||
#remove comments and empty lines
|
||||
cat lang_en.txt | sed '/^$/d;/^#/d'
|
||||
else
|
||||
#remove comments and empty lines, print lines with translated text only
|
||||
cat lang_en_$1.txt | sed '/^$/d;/^#/d' | sed -n 'n;p'
|
||||
fi | sed 's/^\"\\x00\"$/\"\"/' > lang_$1.tmp
|
||||
#create lang_xx.dat (binary text data file)
|
||||
# cat lang_$1.tmp | sed 's/^\"/\/bin\/echo -e \"/;s/"$/\\x00\"/' > lang_$1.shx
|
||||
cat lang_$1.tmp | sed 's/^\"/\/bin\/echo -e -n \"/;s/"$/\\x00\"/' | sh >lang_$1.dat
|
||||
#calculate number of strings
|
||||
count=$(grep -c '^"' lang_$1.tmp)
|
||||
echo "count="$count >&2
|
||||
#calculate text data offset
|
||||
offs=$((16 + 2 * $count))
|
||||
echo "offs="$offs >&2
|
||||
#calculate text data size
|
||||
size=$(($offs + $(wc -c lang_$1.dat | cut -f1 -d' ')))
|
||||
echo "size="$size >&2
|
||||
#write header with empty signature and checksum
|
||||
write_header $1 $size $count 0x0000 0x00000000
|
||||
#write offset table
|
||||
offs_hex=$(cat lang_$1.tmp | sed 's/^\"//;s/\"$//' |\
|
||||
sed 's/\\x[0-9a-f][0-9a-f]/\./g;s/\\[0-7][0-7][0-7]/\./g;s/\ /\./g' |\
|
||||
awk 'BEGIN { o='$offs';} { h=int(o/256); printf("\\x%02x\\x%02x",int(o-256*h), h); o+=(length($0)+1); }')
|
||||
/bin/echo -n -e "$offs_hex" | dd of=./lang_$1.bin bs=1 seek=16 conv=notrunc 2>/dev/null
|
||||
#write binary text data
|
||||
dd if=./lang_$1.dat of=./lang_$1.bin bs=1 seek=$offs conv=notrunc 2>/dev/null
|
||||
#write signature
|
||||
if [ "$1" != "en" ]; then
|
||||
dd if=lang_en.bin of=lang_$1.bin bs=1 count=4 skip=6 seek=12 conv=notrunc 2>/dev/null
|
||||
fi
|
||||
#calculate and update checksum
|
||||
chsum=$(cat lang_$1.bin | xxd | cut -c11-49 | tr ' ' "\n" | sed '/^$/d' | awk 'BEGIN { sum = 0; } { sum += strtonum("0x"$1); if (sum > 0xffff) sum -= 0x10000; } END { printf("%x\n", sum); }')
|
||||
/bin/echo -n -e $(echo -n $((0x$chsum)) | awk "$awk_ui16") |\
|
||||
dd of=lang_$1.bin bs=1 count=2 seek=8 conv=notrunc 2>/dev/null
|
||||
#remove temporary files
|
||||
# rm -f lang_$1.tmp
|
||||
# rm -f lang_$1.dat
|
||||
}
|
||||
|
||||
if [ -z "$1" ]; then set 'all'; fi
|
||||
|
||||
if [ "$1" = "all" ]; then
|
||||
generate_binary 'en'
|
||||
generate_binary 'cz'
|
||||
generate_binary 'de'
|
||||
generate_binary 'es'
|
||||
generate_binary 'fr'
|
||||
generate_binary 'it'
|
||||
generate_binary 'pl'
|
||||
else
|
||||
generate_binary $1
|
||||
fi
|
||||
|
||||
finish 0
|
75
lang/lang-check.py
Normal file
75
lang/lang-check.py
Normal file
|
@ -0,0 +1,75 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Check lang files."""
|
||||
from argparse import ArgumentParser
|
||||
from traceback import print_exc
|
||||
from sys import stderr
|
||||
|
||||
|
||||
def parse_txt(lang, no_warning):
|
||||
"""Parse txt file and check strings to display definition."""
|
||||
if lang == "en":
|
||||
file_path = "lang_en.txt"
|
||||
else:
|
||||
file_path = "lang_en_%s.txt" % lang
|
||||
|
||||
lines = 1
|
||||
with open(file_path) as src:
|
||||
while True:
|
||||
comment = src.readline().split(' ')
|
||||
src.readline() # source
|
||||
translation = src.readline()[:-1]
|
||||
|
||||
cols = None
|
||||
rows = None
|
||||
for item in comment[1:]:
|
||||
key, val = item.split('=')
|
||||
if key == 'c':
|
||||
cols = int(val)
|
||||
elif key == 'r':
|
||||
rows = int(val)
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"Unknown display definition %s on line %d" %
|
||||
(' '.join(comment), lines))
|
||||
if cols is None and rows is None:
|
||||
if not no_warning:
|
||||
print("[W]: No display definition on line %d" % lines)
|
||||
cols = len(translation) # propably fullscreen
|
||||
if rows is None:
|
||||
rows = 1
|
||||
|
||||
if len(translation)-2 > cols*rows:
|
||||
stderr.write(
|
||||
"[E]: Text %s is longer then definiton on line %d\n" %
|
||||
(translation, lines))
|
||||
stderr.flush()
|
||||
|
||||
if len(src.readline()) != 1: # empty line
|
||||
break
|
||||
lines += 4
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function."""
|
||||
parser = ArgumentParser(
|
||||
description=__doc__,
|
||||
usage="$(prog)s lang")
|
||||
parser.add_argument(
|
||||
"lang", nargs='?', default="en", type=str,
|
||||
help="Check lang file (en|cs|de|es|fr|it|pl)")
|
||||
parser.add_argument(
|
||||
"--no-warning", action="store_true",
|
||||
help="Disable warnings")
|
||||
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
parse_txt(args.lang, args.no_warning)
|
||||
return 0
|
||||
except Exception as exc:
|
||||
print_exc()
|
||||
parser.error("%s" % exc)
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit(main())
|
75
lang/lang-check.sh
Normal file
75
lang/lang-check.sh
Normal file
|
@ -0,0 +1,75 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# lang_check.sh - multi-language support script
|
||||
# check lang_xx.bin (language binary file)
|
||||
#
|
||||
# Input files:
|
||||
# lang_$1.bin
|
||||
# lang_en.txt or lang_en_$1.txt
|
||||
#
|
||||
#
|
||||
|
||||
#set 'cz'
|
||||
|
||||
#dictionary txt file
|
||||
fn_t=lang_en_$1.txt
|
||||
if [ "$1" = "en" ]; then fn_t=lang_en.txt; fi
|
||||
#binary file to check
|
||||
fn_b=lang_$1.bin
|
||||
|
||||
#check txt dictionary file
|
||||
echo -n "dictionary file: $fn_t"
|
||||
if [ -e $fn_t ]; then echo " - OK"; else echo " - Not found!"; exit 1; fi
|
||||
|
||||
#create lang_xx.tmp - different processing for 'en' language
|
||||
if [ "$1" = "en" ]; then
|
||||
#remove comments and empty lines
|
||||
cat lang_en.txt | sed '/^$/d;/^#/d'
|
||||
else
|
||||
#remove comments and empty lines, print lines with translated text only
|
||||
cat lang_en_$1.txt | sed '/^$/d;/^#/d' | sed -n 'n;p'
|
||||
fi | sed 's/^\"\\x00\"$/\"\"/' > lang_$1.tmp
|
||||
|
||||
count_txt=$(grep -c '^"' lang_$1.tmp)
|
||||
|
||||
echo -n "language bin file: $fn_b"
|
||||
if [ -e $fn_b ]; then echo " - OK"; else echo " - Not found!"; exit 1; fi
|
||||
|
||||
#read header and convert to hex
|
||||
header=$(dd if=$fn_b bs=1 count=16 2>/dev/null | xxd | cut -c11-49 | sed 's/\([0-9a-f][0-9a-f]\)[\ ]*/\1 /g')
|
||||
echo "header='$header'"
|
||||
magic=0x$(echo $header | tr -d ' ' | cut -c1-8)
|
||||
echo "magic='$magic'"
|
||||
size=$(echo $header | tr -d ' ' | cut -c9-12)
|
||||
size=0x${size:2:2}${size:0:2}
|
||||
echo "size='$size' ($(($size)))"
|
||||
count=$(echo $header | tr -d ' ' | cut -c13-16)
|
||||
count=0x${count:2:2}${count:0:2}
|
||||
echo "count='$count' ($(($count)))"
|
||||
o=0
|
||||
l=0
|
||||
#create lang_xx_1.tmp (temporary text file from binary data)
|
||||
(dd if=$fn_b bs=1 count=$((2*$count)) skip=16 2>/dev/null | xxd | cut -c11-49 | tr ' ' "\n" |\
|
||||
sed 's/\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)/\2\1 /g;/^$/d'; printf "%04x\n" $(($size)) ) |\
|
||||
while read offs; do
|
||||
if [ $o -ne 0 ]; then
|
||||
l=$((0x$offs - $o))
|
||||
echo -n '"'
|
||||
dd if=$fn_b bs=1 count=$((l-1)) skip=$o 2>/dev/null
|
||||
echo '"'
|
||||
fi
|
||||
o=$((0x$offs))
|
||||
done > lang_$1_1.tmp
|
||||
#create lang_xx_2.tmp (temporary text file from dictionary)
|
||||
cat lang_$1.tmp | sed 's/^\"/printf \"\\x22/;s/"$/\\x22\\x0a\"/' | sh >lang_$1_2.tmp
|
||||
#compare temporary files
|
||||
diff -a lang_$1_1.tmp lang_$1_2.tmp >lang_$1_check.dif
|
||||
dif=$(cat lang_$1_check.dif)
|
||||
if [ -z "$dif" ]; then
|
||||
echo 'binary data OK'
|
||||
else
|
||||
echo 'binary data NG!'
|
||||
fi
|
||||
|
||||
read
|
||||
exit
|
61
lang/lang-clean.sh
Normal file
61
lang/lang-clean.sh
Normal file
|
@ -0,0 +1,61 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# clean.sh - multi-language support script
|
||||
# Remove all language output files from lang folder.
|
||||
#
|
||||
|
||||
result=0
|
||||
|
||||
rm_if_exists()
|
||||
{
|
||||
if [ -e $1 ]; then
|
||||
echo -n " removing '$1'..." >&2
|
||||
if rm $1; then
|
||||
echo "OK" >&2
|
||||
else
|
||||
echo "NG!" >&2
|
||||
result=1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
clean_lang()
|
||||
{
|
||||
if [ "$1" = "en" ]; then
|
||||
rm_if_exists lang_$1.tmp
|
||||
else
|
||||
rm_if_exists lang_$1.tmp
|
||||
rm_if_exists lang_en_$1.tmp
|
||||
rm_if_exists lang_en_$1.dif
|
||||
rm_if_exists lang_$1.ofs
|
||||
rm_if_exists lang_$1.txt
|
||||
fi
|
||||
rm_if_exists lang_$1_check.dif
|
||||
rm_if_exists lang_$1.bin
|
||||
rm_if_exists lang_$1.dat
|
||||
rm_if_exists lang_$1_1.tmp
|
||||
rm_if_exists lang_$1_2.tmp
|
||||
}
|
||||
|
||||
echo "lang-clean.sh started" >&2
|
||||
|
||||
clean_lang en
|
||||
clean_lang cz
|
||||
clean_lang de
|
||||
clean_lang es
|
||||
clean_lang fr
|
||||
clean_lang it
|
||||
clean_lang pl
|
||||
|
||||
echo -n "lang-clean.sh finished" >&2
|
||||
if [ $result -eq 0 ]; then
|
||||
echo " with success" >&2
|
||||
else
|
||||
echo " with errors!" >&2
|
||||
fi
|
||||
|
||||
case "$-" in
|
||||
*i*) echo "press enter key" >&2; read ;;
|
||||
esac
|
||||
|
||||
exit $result
|
133
lang/lang-export.sh
Normal file
133
lang/lang-export.sh
Normal file
|
@ -0,0 +1,133 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# lang-export.sh - multi-language support script
|
||||
# for generating lang_xx.po
|
||||
#
|
||||
|
||||
# relative path to source folder
|
||||
SRCDIR="../Firmware"
|
||||
|
||||
# selected language is 1st argument (cz, de, ...)
|
||||
LNG=$1
|
||||
|
||||
# if no arguments, 'all' is selected (all po and also pot will be generated)
|
||||
if [ -z "$LNG" ]; then LNG=all; fi
|
||||
|
||||
# if 'all' is selected, script will generate all po files and also pot file
|
||||
if [ "$LNG" = "all" ]; then
|
||||
./lang-export.sh en
|
||||
./lang-export.sh cz
|
||||
./lang-export.sh de
|
||||
./lang-export.sh es
|
||||
./lang-export.sh fr
|
||||
./lang-export.sh it
|
||||
./lang-export.sh pl
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# language code (iso639-1) is equal to LNG
|
||||
LNGISO=$LNG
|
||||
# exception for 'cz' (code='cs')
|
||||
if [ "$LNG" = "cz" ]; then LNGISO=cs; fi
|
||||
|
||||
# po/pot creation/revision date
|
||||
DATE=$(date)
|
||||
|
||||
# if 'en' is selected, generate pot instead of po
|
||||
if [ "$LNG" = "en" ]; then
|
||||
INFILE=lang_en.txt
|
||||
OUTFILE=po/Firmware.pot
|
||||
LNGNAME="English"
|
||||
else
|
||||
# language name in english
|
||||
LNGNAME=$(\
|
||||
case "$LNG" in
|
||||
*cz*) echo "Czech" ;;
|
||||
*de*) echo "German" ;;
|
||||
*es*) echo "Spanish" ;;
|
||||
*fr*) echo "French" ;;
|
||||
*it*) echo "Italian" ;;
|
||||
*pl*) echo "Polish" ;;
|
||||
esac)
|
||||
# unknown language - error
|
||||
if [ -z "LNGNAME" ]; then
|
||||
echo "Invalid argument '$LNG'."
|
||||
exit 1
|
||||
fi
|
||||
INFILE=lang_en_$LNG.txt
|
||||
OUTFILE=po/Firmware_$LNGISO.po
|
||||
fi
|
||||
|
||||
# remove output file if exists
|
||||
if [ -e $OUTFILE ]; then rm -f -v $OUTFILE; fi
|
||||
|
||||
echo "lang-export.sh started"
|
||||
|
||||
#total strings
|
||||
CNTTXT=$(grep '^#' -c $INFILE)
|
||||
#not translated strings
|
||||
CNTNT=$(grep '^\"\\x00\"' -c $INFILE)
|
||||
echo " $CNTTXT texts, $CNTNT not translated"
|
||||
|
||||
# list .cpp, .c and .h files from source folder
|
||||
SRCFILES=$(ls "$SRCDIR"/*.cpp "$SRCDIR"/*.c "$SRCDIR"/*.h)
|
||||
|
||||
echo " selected language=$LNGNAME"
|
||||
|
||||
# write po/pot header
|
||||
(
|
||||
echo "# Translation of Prusa-Firmware into $LNGNAME."
|
||||
echo "#"
|
||||
echo 'msgid ""'
|
||||
echo 'msgstr ""'
|
||||
echo '"MIME-Version: 1.0\n"'
|
||||
echo '"Content-Type: text/plain; charset=UTF-8\n"'
|
||||
echo '"Content-Transfer-Encoding: 8bit\n"'
|
||||
echo '"Language: '$LNGISO'\n"'
|
||||
echo '"Project-Id-Version: Prusa-Firmware\n"'
|
||||
echo '"POT-Creation-Date: '$DATE'\n"'
|
||||
echo '"PO-Revision-Date: '$DATE'\n"'
|
||||
echo '"Language-Team: \n"'
|
||||
echo '"X-Generator: Poedit 2.0.7\n"'
|
||||
echo '"X-Poedit-SourceCharset: UTF-8\n"'
|
||||
echo '"Last-Translator: \n"'
|
||||
echo '"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"'
|
||||
echo
|
||||
) >$OUTFILE
|
||||
|
||||
#loop over all messages
|
||||
s0=''
|
||||
s1=''
|
||||
s2=''
|
||||
num=1
|
||||
(cat $INFILE | sed "s/\\\\/\\\\\\\\/g" | while read -r s; do
|
||||
if [ "$s" = "" ]; then
|
||||
echo " processing $num of $CNTTXT" >&2
|
||||
# write po/pot item
|
||||
(
|
||||
if [ -z "$s2" ]; then s2=$s1; s1=$s0; s0='""'; fi
|
||||
search=$(/bin/echo -e "$s1")
|
||||
found=$(grep -m1 -n -F "$search" $SRCFILES | head -n1 | cut -f1-2 -d':' | sed "s/^.*\///")
|
||||
echo "$s2" | sed 's/ c=0//;s/ r=0//;s/^#/# /'
|
||||
echo "#: $found"
|
||||
/bin/echo -e "msgid $s1"
|
||||
if [ "$s0" = "\"\\\\x00\"" ]; then
|
||||
echo 'msgstr ""'
|
||||
else
|
||||
/bin/echo -e "msgstr $s0"
|
||||
fi
|
||||
echo
|
||||
)
|
||||
num=$((num+1))
|
||||
fi
|
||||
s2=$s1
|
||||
s1=$s0
|
||||
s0=$s
|
||||
done >>$OUTFILE) 2>&1
|
||||
|
||||
#replace LF with CRLF
|
||||
sync
|
||||
sed -i 's/$/\r/' $OUTFILE
|
||||
|
||||
echo "lang-export.sh finished"
|
||||
exit 0
|
157
lang/lang-import.sh
Normal file
157
lang/lang-import.sh
Normal file
|
@ -0,0 +1,157 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# lang-import.sh - multi-language support script
|
||||
# for importing translated xx.po
|
||||
|
||||
LNG=$1
|
||||
# if no arguments, 'all' is selected (all po and also pot will be generated)
|
||||
if [ -z "$LNG" ]; then LNG=all; fi
|
||||
|
||||
# if 'all' is selected, script will generate all po files and also pot file
|
||||
if [ "$LNG" = "all" ]; then
|
||||
./lang-import.sh cz
|
||||
./lang-import.sh de
|
||||
./lang-import.sh es
|
||||
./lang-import.sh fr
|
||||
./lang-import.sh it
|
||||
./lang-import.sh pl
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# language code (iso639-1) is equal to LNG
|
||||
LNGISO=$LNG
|
||||
# exception for 'cz' (code='cs')
|
||||
if [ "$LNG" = "cz" ]; then LNGISO=cs; fi
|
||||
|
||||
# cd to input folder
|
||||
cd po/new
|
||||
|
||||
# check if input file exists
|
||||
if ! [ -e $LNGISO.po ]; then
|
||||
echo "Input file $LNGISO.po not found!" >&2
|
||||
exit -1
|
||||
fi
|
||||
|
||||
#convert '\\e' sequencies to 'x1b' and '\\' to '\'
|
||||
cat $LNGISO.po | sed 's/\\e/\\x1b/g;s/\\\\/\\/g' > $LNG'_filtered.po'
|
||||
|
||||
#replace '\n' with ' ' (single space)
|
||||
sed -i 's/ \\n/ /g;s/\\n/ /g' $LNG'_filtered.po'
|
||||
|
||||
#replace in czech translation
|
||||
if [ "$LNG" = "cz" ]; then
|
||||
#replace 'ž' with 'z'
|
||||
sed -i 's/\xc5\xbe/z/g' $LNG'_filtered.po'
|
||||
#replace 'ì' with 'e'
|
||||
sed -i 's/\xc4\x9b/e/g' $LNG'_filtered.po'
|
||||
#replace 'í' with 'i'
|
||||
sed -i 's/\xc3\xad/i/g' $LNG'_filtered.po'
|
||||
#replace 'ø' with 'r'
|
||||
sed -i 's/\xc5\x99/r/g' $LNG'_filtered.po'
|
||||
#replace 'è' with 'c'
|
||||
sed -i 's/\xc4\x8d/c/g' $LNG'_filtered.po'
|
||||
#replace 'á' with 'a'
|
||||
sed -i 's/\xc3\xa1/a/g' $LNG'_filtered.po'
|
||||
#replace 'é' with 'e'
|
||||
sed -i 's/\xc3\xa9/e/g' $LNG'_filtered.po'
|
||||
fi
|
||||
|
||||
#replace in german translation https://en.wikipedia.org/wiki/German_orthography
|
||||
if [ "$LNG" = "de" ]; then
|
||||
#replace 'ä' with 'ae'
|
||||
sed -i 's/\xc3\xa4/ae/g' $LNG'_filtered.po'
|
||||
#replace 'Ä' with 'Ae'
|
||||
sed -i 's/\xc3\x84/Ae/g' $LNG'_filtered.po'
|
||||
#replace 'ü' with 'ue'
|
||||
sed -i 's/\xc3\xbc/ue/g' $LNG'_filtered.po'
|
||||
#replace 'Ü' with 'Ue'
|
||||
sed -i 's/\xc3\x9c/Ue/g' $LNG'_filtered.po'
|
||||
#replace 'ö' with 'oe'
|
||||
sed -i 's/\xc3\xb6/oe/g' $LNG'_filtered.po'
|
||||
#replace 'Ö' with 'Oe'
|
||||
sed -i 's/\xc3\x96/Oe/g' $LNG'_filtered.po'
|
||||
#replace 'ß' with 'ss'
|
||||
sed -i 's/\xc3\x9f/ss/g' $LNG'_filtered.po'
|
||||
fi
|
||||
|
||||
#replace in spain translation
|
||||
if [ "$LNG" = "es" ]; then
|
||||
#replace 'á' with 'a'
|
||||
sed -i 's/\xc3\xa1/a/g' $LNG'_filtered.po'
|
||||
#replace '¿' with '?'
|
||||
sed -i 's/\xc2\xbf/?/g' $LNG'_filtered.po'
|
||||
#replace 'ó' with 'o'
|
||||
sed -i 's/\xc3\xb3/o/g' $LNG'_filtered.po'
|
||||
#replace 'é' with 'e'
|
||||
sed -i 's/\xc3\xa9/e/g' $LNG'_filtered.po'
|
||||
#replace 'í' with 'i'
|
||||
sed -i 's/\xc3\xad/i/g' $LNG'_filtered.po'
|
||||
#replace '!' with '!'
|
||||
sed -i 's/\xc2\xa1/!/g' $LNG'_filtered.po'
|
||||
#replace 'n~' with 'n'
|
||||
sed -i 's/\xc3\xb1/n/g' $LNG'_filtered.po'
|
||||
fi
|
||||
|
||||
#replace in french translation https://en.wikipedia.org/wiki/French_orthography
|
||||
if [ "$LNG" = "fr" ]; then
|
||||
#replace 'á' with 'a' (right)
|
||||
sed -i 's/\xc3\xa1/a/g' $LNG'_filtered.po'
|
||||
#replace 'Á' with 'A' (right)
|
||||
sed -i 's/\xc3\x81/A/g' $LNG'_filtered.po'
|
||||
#replace 'à' with 'a' (left)
|
||||
sed -i 's/\xc3\xa0/a/g' $LNG'_filtered.po'
|
||||
#replace 'À' with 'A' (left)
|
||||
sed -i 's/\xc3\x80/A/g' $LNG'_filtered.po'
|
||||
#replace 'é' with 'e' (right)
|
||||
sed -i 's/\xc3\xa9/e/g' $LNG'_filtered.po'
|
||||
#replace 'É' with 'E' (right)
|
||||
sed -i 's/\xc3\x89/E/g' $LNG'_filtered.po'
|
||||
#replace 'è' with 'e' (left)
|
||||
sed -i 's/\xc3\xa8/e/g' $LNG'_filtered.po'
|
||||
#replace 'È' with 'E' (left)
|
||||
sed -i 's/\xc3\x88/E/g' $LNG'_filtered.po'
|
||||
fi
|
||||
|
||||
#replace in italian translation
|
||||
if [ "$LNG" = "it" ]; then
|
||||
#replace 'é' with 'e' (left)
|
||||
sed -i 's/\xc3\xa8/e/g' $LNG'_filtered.po'
|
||||
#replace 'á' with 'a' (left)
|
||||
sed -i 's/\xc3\xa0/a/g' $LNG'_filtered.po'
|
||||
#replace 'ó' with 'o' (left)
|
||||
sed -i 's/\xc3\xb2/o/g' $LNG'_filtered.po'
|
||||
#replace 'ú' with 'u' (left)
|
||||
sed -i 's/\xc3\xb9/u/g' $LNG'_filtered.po'
|
||||
#replace 'é' with 'e'
|
||||
sed -i 's/\xc3\xa9/e/g' $LNG'_filtered.po'
|
||||
#replace 'É' with 'E' (left)
|
||||
sed -i 's/\xc3\x88/E/g' $LNG'_filtered.po'
|
||||
fi
|
||||
|
||||
#replace in polish translation
|
||||
#if [ "$LNG" = "pl" ]; then
|
||||
#fi
|
||||
|
||||
#check for nonasci characters
|
||||
if grep --color='auto' -P -n '[^\x00-\x7F]' $LNG'_filtered.po' >nonasci.txt; then
|
||||
exit
|
||||
fi
|
||||
|
||||
#join lines with multi-line string constants
|
||||
cat $LNG'_filtered.po' | sed ':a;N;$!ba;s/\x22\n\x22//g' > $LNG'_new.po'
|
||||
|
||||
#generate new dictionary
|
||||
cat ../../lang_en.txt | sed 's/\\/\\\\/g' | while read -r s; do
|
||||
/bin/echo -e "$s"
|
||||
if [ "${s:0:1}" = "\"" ]; then
|
||||
# /bin/echo -e "$s"
|
||||
s=$(/bin/echo -e "$s")
|
||||
s2=$(grep -F -A1 -B0 "$s" "$LNG"_new.po | tail -n1 | sed 's/^msgstr //')
|
||||
if [ -z "$s2" ]; then
|
||||
echo '"\x00"'
|
||||
else
|
||||
echo "$s2"
|
||||
fi
|
||||
# echo
|
||||
fi
|
||||
done > lang_en_$LNG.txt
|
1079
lang/lang_en.txt
Normal file
1079
lang/lang_en.txt
Normal file
File diff suppressed because it is too large
Load diff
1439
lang/lang_en_cz.txt
Normal file
1439
lang/lang_en_cz.txt
Normal file
File diff suppressed because it is too large
Load diff
1439
lang/lang_en_de.txt
Normal file
1439
lang/lang_en_de.txt
Normal file
File diff suppressed because it is too large
Load diff
1439
lang/lang_en_es.txt
Normal file
1439
lang/lang_en_es.txt
Normal file
File diff suppressed because it is too large
Load diff
1440
lang/lang_en_fr.txt
Normal file
1440
lang/lang_en_fr.txt
Normal file
File diff suppressed because it is too large
Load diff
1439
lang/lang_en_it.txt
Normal file
1439
lang/lang_en_it.txt
Normal file
File diff suppressed because it is too large
Load diff
1439
lang/lang_en_pl.txt
Normal file
1439
lang/lang_en_pl.txt
Normal file
File diff suppressed because it is too large
Load diff
1812
lang/po/Firmware.pot
Normal file
1812
lang/po/Firmware.pot
Normal file
File diff suppressed because it is too large
Load diff
1812
lang/po/Firmware_cs.po
Normal file
1812
lang/po/Firmware_cs.po
Normal file
File diff suppressed because it is too large
Load diff
1817
lang/po/Firmware_de.po
Normal file
1817
lang/po/Firmware_de.po
Normal file
File diff suppressed because it is too large
Load diff
1812
lang/po/Firmware_es.po
Normal file
1812
lang/po/Firmware_es.po
Normal file
File diff suppressed because it is too large
Load diff
1817
lang/po/Firmware_fr.po
Normal file
1817
lang/po/Firmware_fr.po
Normal file
File diff suppressed because it is too large
Load diff
1812
lang/po/Firmware_it.po
Normal file
1812
lang/po/Firmware_it.po
Normal file
File diff suppressed because it is too large
Load diff
1812
lang/po/Firmware_pl.po
Normal file
1812
lang/po/Firmware_pl.po
Normal file
File diff suppressed because it is too large
Load diff
1812
lang/po/new/cs.po
Normal file
1812
lang/po/new/cs.po
Normal file
File diff suppressed because it is too large
Load diff
1817
lang/po/new/de.po
Normal file
1817
lang/po/new/de.po
Normal file
File diff suppressed because it is too large
Load diff
1812
lang/po/new/es.po
Normal file
1812
lang/po/new/es.po
Normal file
File diff suppressed because it is too large
Load diff
1817
lang/po/new/fr.po
Normal file
1817
lang/po/new/fr.po
Normal file
File diff suppressed because it is too large
Load diff
1812
lang/po/new/it.po
Normal file
1812
lang/po/new/it.po
Normal file
File diff suppressed because it is too large
Load diff
1812
lang/po/new/pl.po
Normal file
1812
lang/po/new/pl.po
Normal file
File diff suppressed because it is too large
Load diff
116
lang/progmem.sh
Normal file
116
lang/progmem.sh
Normal file
|
@ -0,0 +1,116 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# progmem.sh - multi-language support script
|
||||
# Examine content of progmem sections (default is progmem1).
|
||||
#
|
||||
# Input files:
|
||||
# $OUTDIR/Firmware.ino.elf
|
||||
# $OUTDIR/sketch/*.o (all object files)
|
||||
#
|
||||
# Output files:
|
||||
# text.sym - formated symbol listing of section '.text'
|
||||
# $PROGMEM.sym - formated symbol listing of section '.progmemX'
|
||||
# $PROGMEM.lss - disassembly listing file
|
||||
# $PROGMEM.hex - variables - hex
|
||||
# $PROGMEM.chr - variables - char escape
|
||||
# $PROGMEM.var - variables - strings
|
||||
# $PROGMEM.txt - text data only (not used)
|
||||
#
|
||||
#
|
||||
# Config:
|
||||
if [ -z "$CONFIG_OK" ]; then eval "$(cat config.sh)"; fi
|
||||
if [ -z "$OUTDIR" ]; then echo 'variable OUTDIR not set!' >&2; exit 1; fi
|
||||
if [ -z "$OBJDIR" ]; then echo 'variable OBJDIR not set!' >&2; exit 1; fi
|
||||
if [ -z "$INOELF" ]; then echo 'variable INOELF not set!' >&2; exit 1; fi
|
||||
if [ -z "$OBJDUMP" ]; then echo 'variable OBJDUMP not set!' >&2; exit 1; fi
|
||||
if [ -z "$CONFIG_OK" ] | [ $CONFIG_OK -eq 0 ]; then echo 'Config NG!' >&2; exit 1; fi
|
||||
#
|
||||
# Program memory used
|
||||
PROGMEM=progmem$1
|
||||
if [ -z "$1" ]; then PROGMEM=progmem1; fi
|
||||
#
|
||||
# Description of process:
|
||||
# 0. check input files
|
||||
# 1. remove output files
|
||||
# 2. list symbol table of section '.text' from output elf file to text.sym (sorted by address)
|
||||
# 3. calculate start and stop address of section '.$PROGMEM'
|
||||
# 4. extract string data from elf file to $PROGMEM.hex
|
||||
# 5. prepare string data for character check and conversion (output to $PROGMEM.chr)
|
||||
# 6. perform character check and conversion (output to $PROGMEM.var and $PROGMEM.txt)
|
||||
#
|
||||
|
||||
echo "progmem.sh started" >&2
|
||||
|
||||
# (0)
|
||||
echo " progmem.sh (0) - checking input files" >&2
|
||||
if [ ! -e $OUTDIR ]; then echo "progmem.sh - file '$INOELF' not found!" >&2; exit 1; fi
|
||||
|
||||
# (1)
|
||||
echo " progmem.sh (1) - removing output files" >&2
|
||||
#remove output files if exists
|
||||
if [ -e text.sym ]; then rm text.sym; fi
|
||||
if [ -e $PROGMEM.sym ]; then rm $PROGMEM.sym; fi
|
||||
if [ -e $PROGMEM.lss ]; then rm $PROGMEM.lss; fi
|
||||
if [ -e $PROGMEM.hex ]; then rm $PROGMEM.hex; fi
|
||||
if [ -e $PROGMEM.chr ]; then rm $PROGMEM.chr; fi
|
||||
if [ -e $PROGMEM.var ]; then rm $PROGMEM.var; fi
|
||||
if [ -e $PROGMEM.txt ]; then rm $PROGMEM.txt; fi
|
||||
|
||||
# (2)
|
||||
echo " progmem.sh (2) - listing symbol table of section '.text'" >&2
|
||||
#list symbols from section '.text' into file text.sym (only address, size and name)
|
||||
#$OBJDUMP -t -j ".text" $INOELF | sort > text.sym
|
||||
$OBJDUMP -t -j ".text" $INOELF | tail -n +5 | grep -E "^[0-9a-f]{8} [gl] [O ]" | cut -c1-9,28-36,37- | sed "/^$/d" | sort > text.sym
|
||||
|
||||
# (3)
|
||||
echo " progmem.sh (3) - calculating start and end address" >&2
|
||||
#calculate start addres of section ".$PROGMEM"
|
||||
PROGMEM_BEG=$(cat text.sym | grep "__loc_pri_start" | while read offs size name; do echo "0x"$offs; done)
|
||||
#calculate stop addres of section ".$PROGMEM"
|
||||
PROGMEM_END=$(cat text.sym | grep "__loc_pri_end" | while read offs size name; do echo "0x"$offs; done)
|
||||
echo " START address = "$PROGMEM_BEG >&2
|
||||
echo " STOP address = "$PROGMEM_END >&2
|
||||
|
||||
# (4)
|
||||
echo " progmem.sh (4) - extracting string data from elf" >&2
|
||||
#dump $PROGMEM data in hex format, cut disassembly (keep hex data only)
|
||||
$OBJDUMP -D -j ".text" -w -z --start-address=$PROGMEM_BEG --stop-address=$PROGMEM_END $INOELF |\
|
||||
tail -n +7 | sed "s/ \t.*$//" > $PROGMEM.lss
|
||||
#convert $PROGMEM.lss to $PROGMEM.hex:
|
||||
# replace empty lines with '|' (variables separated by empty lines)
|
||||
# remove address from multiline variables (keep address at first variable line only)
|
||||
# remove '<' and '>:', remove whitespace at end of lines
|
||||
# remove line-endings, replace separator with '\n' (join hex data lines - each line will contain single variable)
|
||||
cat $PROGMEM.lss | sed -E 's/^$/|/;s/^ ....:\t//;s/[ ]*$/ /' | tr -d '\n' | tr '|' '\n' |\
|
||||
sed "s/^ //;s/<//;s/>:/ /;s/00 [1-9a-f][1-9a-f] $/00 /; s/ $//" > $PROGMEM.hex
|
||||
|
||||
# (5)
|
||||
echo " progmem.sh (5) - preparing string data" >&2
|
||||
#convert $PROGMEM.hex to $PROGMEM.chr (prepare string data for character check and conversion)
|
||||
# replace first space with tab
|
||||
# replace second and third space with tab and space
|
||||
# replace all remaining spaces with '\x'
|
||||
# replace all tabs with spaces
|
||||
cat $PROGMEM.hex | sed 's/ /\t/;s/ /\t /;s/ /\\x/g;s/\t/ /g' > $PROGMEM.chr
|
||||
|
||||
# (6)
|
||||
#convert $PROGMEM.chr to $PROGMEM.var (convert data to text)
|
||||
echo " progmem.sh (6) - converting string data" >&2
|
||||
(\
|
||||
echo "/bin\/echo -e \\"; \
|
||||
cat $PROGMEM.chr | \
|
||||
sed 's/ \\xff\\xff/ /;' | \
|
||||
sed 's/\\x22/\\\\\\x22/g;' | \
|
||||
sed 's/\\x1b/\\\\\\x1b/g;' | \
|
||||
sed 's/\\x01/\\\\\\x01/g;' | \
|
||||
sed 's/\\xf8/\\\\\\xf8/g;' | \
|
||||
sed 's/\\x0a/\\\\\\x0a/g;' | \
|
||||
sed 's/\\x00$/\n/;s/^/\"/;s/$/\"\\/'; \
|
||||
) | sh > $PROGMEM.var
|
||||
|
||||
#this step can be omitted because .txt file is not used
|
||||
cat $PROGMEM.var | sed 's/\r/\n/g' | sed -E 's/^[0-9a-f]{8} [^ ]* //' >$PROGMEM.txt
|
||||
|
||||
echo "progmem.sh finished" >&2
|
||||
|
||||
exit 0
|
48
lang/readme.txt
Normal file
48
lang/readme.txt
Normal file
|
@ -0,0 +1,48 @@
|
|||
Nova podpora vice jazyku ve firmware
|
||||
|
||||
|
||||
Zmeny oproti stavajicimu frameworku:
|
||||
1. Deklarace lokalizovanych textu primo v kodu, neni nutne udrzovat tabulky.
|
||||
2. Zatim dvoj jazycna verze (en_cz, en_de atd). Moznost rozsirit na vicejazycnou (en_cz_de - pro MK2).
|
||||
3. Moznost vyberu druheho jazyka ulozeneho v SPI flash (nebude zabirat misto v interni flash, pouze MK3).
|
||||
5. Bash postbuild proces namisto perloveho skriptu + nastroje na spravu slovniku.
|
||||
|
||||
Popis:
|
||||
Novy framework je trochu podobny jako znamy i18n20, ale sity na miru pro AVR atmega s ohledem na maximalni jednoduchost a usporu interni flashe.
|
||||
Stringy ktere maji byt prelozene se deklaruji pomoci specialnich maker, zbytek obstara postbuild.
|
||||
Vsechny lokalizovane texty se nachazi ve specialni sekci, v pripade AVR musi byt stringy umisteny v dolnich 64kB flash - tzv 'progmem'.
|
||||
Po zbuildovani arduinem bude fungovat pouze anglictina, je treba spustit postbuild ktery na zaklade slovniku doplni data sekundarniho jazka a vytvori modifikovany hexfile.
|
||||
Jedina data ktera je treba udrzovat jsou slovniky pro preklad. Jsou to textove soubory kde je vzdy sparovan anglicky text s prelozenym textem.
|
||||
Kazdy text ve slovniku je jeden radek, muze obsahovat specialni znaky v hexadecimalni podobe (e.g. '\x0a'). Nasledujici radek je vzdy prelozeny text.
|
||||
Tento jednoduchy format je zvolen proto aby bylo mozno slovniky a proces prekladu spravovat jen pomoci gitu a nekolika skriptu.
|
||||
|
||||
Pokud pridame nebo zmenime nejaky text v kodu, zmeni se po zbuildovani a spusteni nastroje 'update.sh' soubor lang_en_code.txt.
|
||||
To je generovany soubor ktery obsahuje vsechny lokalizovane texty pouzite v kodu setridene podle abecedy.
|
||||
V gitu uvidime zmenu kterou rucne preneseme do slovniku lang_en_xx.txt, zaroven vytvorime pozadavek na preklad ci korekturu pozadovaneho textu.
|
||||
Pokud pridame nebo zmenime nejaky text ve slovnikach, zmeni se po spusteni nastroje 'update.sh' soubor lang_en_dict.txt.
|
||||
Ten obsahuje vsechny lokalizovane texty ze slovniku (v anglictine), respektive mnozinu jejich sjednoceni.
|
||||
V idealnim pripade by soubory lang_en_code.txt a lang_en_dict.txt mely byt totozne.
|
||||
Pokud se zmeni slovnik, je treba znovu vygenerovat binarni soubory lang_en_xx.bin.
|
||||
|
||||
|
||||
Pouziti v kodu, priklady:
|
||||
|
||||
1. deklarace lokalizovaneho textu v kodu - makro '_i':
|
||||
puts_P(_i("Kill all humans!")); //v cz vypise "Zabit vsechny lidi!"
|
||||
|
||||
2. deklarace lokalizovaneho textu jako globalni konstanty - makro 'PROGMEM_I1' a 'ISTR':
|
||||
const char MSG_PREHEAT[] PROGMEM_I1 = ISTR("Preheat"); //deklarace
|
||||
puts_P(get_translation(MSG_PREHEAT)); //v cz vypise "Predehrev"
|
||||
|
||||
3. fukce get_translation - zkratka makro '_T':
|
||||
puts_P(_T(MSG_PREHEAT)); //v cz vypise "Predehrev"
|
||||
|
||||
4. deklarace lokalizovaneho textu jako lokalni promenne - makro '_I':
|
||||
const char* text = preheat?_I("Preheat"):_I("Cooldown");
|
||||
puts_P(_T(text)); //v cz vypise "Predehrev" nebo "Zchlazeni"
|
||||
|
||||
5. deklarace nelokalizovaneho textu - makro 'PROGMEM_N1' a '_n' nebo '_N':
|
||||
const char MSG_MK3[] PROGMEM_N1 = "MK3"; //deklarace
|
||||
const char* text = _n("MK3");
|
||||
nebo
|
||||
const char* text = _N("MK3");
|
68
lang/textaddr.sh
Normal file
68
lang/textaddr.sh
Normal file
|
@ -0,0 +1,68 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# textaddr.sh - multi-language support script
|
||||
# Compile progmem1.var and lang_en.txt files to textaddr.txt file (mapping of progmem addreses to text idenifiers)
|
||||
#
|
||||
# Input files:
|
||||
# progmem1.var
|
||||
# lang_en.txt
|
||||
#
|
||||
# Output files:
|
||||
# textaddr.txt
|
||||
#
|
||||
#
|
||||
# Dscription of process:
|
||||
# check if input files exists
|
||||
# create sorted list of strings from progmem1.var and lang_en.txt
|
||||
# lines from progmem1.var will contain addres (8 chars) and english text
|
||||
# lines from lang_en.txt will contain linenumber and english text
|
||||
# after sort this will generate pairs of lines (line from progmem1 first)
|
||||
# result of sort is compiled with simple script and stored into file textaddr.txt
|
||||
#
|
||||
|
||||
echo "textaddr.sh started" >&2
|
||||
|
||||
if [ ! -e progmem1.var ]; then echo 'textaddr.sh - file progmem1.var not found!' >&2; exit 1; fi
|
||||
if [ ! -e lang_en.txt ]; then echo 'textaddr.sh - file lang_en.txt not found!' >&2; exit 1; fi
|
||||
addr=''
|
||||
text=''
|
||||
(cat progmem1.var | sed -E "s/^([^ ]*) ([^ ]*) (.*)/\1 \"\3\"/";\
|
||||
cat lang_en.txt | sed "/^$/d;/^#/d" | sed = | sed '{N;s/\n/ /}') |\
|
||||
sort -k2 |\
|
||||
sed "s/\\\/\\\\\\\/g" | while read num txt; do
|
||||
if [ ${#num} -eq 8 ]; then
|
||||
if [ -z "$addr" ]; then
|
||||
addr=$num
|
||||
else
|
||||
if [ "$text" = "$txt" ]; then
|
||||
addr="$addr $num"
|
||||
else
|
||||
echo "ADDR NF $addr $text"
|
||||
addr=$num
|
||||
fi
|
||||
fi
|
||||
text=$txt
|
||||
else
|
||||
if [ -z "$addr" ]; then
|
||||
if ! [ -z "$num" ]; then echo "TEXT NF $num $txt"; fi
|
||||
else
|
||||
if [ "$text" = "$txt" ]; then
|
||||
if [ ${#addr} -eq 8 ]; then
|
||||
echo "ADDR OK $addr $num"
|
||||
else
|
||||
echo "$addr" | sed "s/ /\n/g" | while read ad; do
|
||||
echo "ADDR OK $ad $num"
|
||||
done
|
||||
fi
|
||||
addr=''
|
||||
text=''
|
||||
else
|
||||
if ! [ -z "$num" ]; then echo "TEXT NF $num $txt"; fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done > textaddr.txt
|
||||
|
||||
echo "textaddr.sh finished" >&2
|
||||
|
||||
exit 0
|
252
lang/translations.md
Normal file
252
lang/translations.md
Normal file
|
@ -0,0 +1,252 @@
|
|||
# Translations
|
||||
|
||||
## Workflow
|
||||
|
||||
- Build firmware
|
||||
- using `build.sh`
|
||||
- using `PF-build.sh` with a `break` before `# build languages`
|
||||
- change to `lang` folder
|
||||
- check if lang scripts being able to run with `config.sh`
|
||||
- if you get `Arduino main folder: NG` message change in `config.sh` `export ARDUINO=C:/arduino-1.8.5` to `export ARDUINO=<Path to your Arduino IDE folder>`
|
||||
-example: `export ARDUINO=D:/Github/Prusa-Firmware/PF-build-env-1.0.6/windows-64`
|
||||
- run `lang-build.sh en` to create english `lang_en.tmp`, `lang_en.dat` and `lang_en.bin` files
|
||||
- change in `fw-build.sh` `IGNORE_MISSING_TEXT=1` to `IGNORE_MISSING_TEXT=0` so it stops with error and generates `not_used.txt` and `not_tran.txt`
|
||||
- run modified `fw-build.sh`
|
||||
- `not_tran.txt` should be reviewed and added as these are potential missing translations
|
||||
- copy `not_tran.txt` as `lang_add.txt`
|
||||
- check if there are things you don't want to translate or must be modifed
|
||||
- als check that the strings do not start with `spaces` as the scripts doesn't handle these well at this moment.
|
||||
- run `lang-add.sh lang_add.txt` to add the missing translations to `lang_en.txt` and `lang_en_??.txt`
|
||||
- `not_used.txt` should only contain mesages that aren't used in this variant like MK2.5 vs MK3
|
||||
- run `fw-clean.sh` to cleanup firmware related files
|
||||
- delete `not_used.txt` and `not_tran.txt`
|
||||
- run `lang-clean.sh` to cleanup language related files
|
||||
- run `lang-export.sh all` to create PO files for translation these are stored in `/lang/po` folder
|
||||
- Send them to translators and reviewers or
|
||||
- copy these to `/lang/po/new` and
|
||||
- translate these with POEdit the newly added messages
|
||||
- easiest way is to choose `Validate`in POEdit as it shows you `errors` and the `missing transalations` / most likely the newly added at the top.
|
||||
- The new translated files are expected in `/lang/po/new` folder so store the received files these
|
||||
- run `lang-import.sh <language code (iso639-1)>` for each newly translated language
|
||||
- script improvement to import "all" and other things would be great.
|
||||
- Double check if something is missing or faulty
|
||||
- run `lang-build.sh` to to create `lang_en.tmp/.dat/.bin` and `lang_en_??.tmp/.dat/.bin` files
|
||||
- run `fw-build.sh` and check if there are still some messages in `not_tran.txt` that need attention
|
||||
- After approval
|
||||
- run `fw-clean.sh` to cleanup firmware related files
|
||||
- run `lang-clean.sh` to cleanup language related files
|
||||
- change in `fw-build.sh` back to `IGNORE_MISSING_TEXT=1`
|
||||
- remove `break` from `PF-build.sh` script if that has been modified
|
||||
- build your firmware with `build.sh`, `PF-build.sh` or how you normally do it.
|
||||
- Check/Test firmware on printer
|
||||
|
||||
## Code / usage
|
||||
There are 2 modes of operation. If `LANG_MODE==0`, only one language is being used (the default compilation approach from plain Arduino IDE).
|
||||
The reset of this explanation is devoted to `LANG_MODE==1`:
|
||||
|
||||
`language.h`:
|
||||
```C++
|
||||
// section .loc_sec (originaly .progmem0) will be used for localized translated strings
|
||||
#define PROGMEM_I2 __attribute__((section(".loc_sec")))
|
||||
// section .loc_pri (originaly .progmem1) will be used for localized strings in english
|
||||
#define PROGMEM_I1 __attribute__((section(".loc_pri")))
|
||||
// section .noloc (originaly progmem2) will be used for not localized strings in english
|
||||
#define PROGMEM_N1 __attribute__((section(".noloc")))
|
||||
#define _I(s) (__extension__({static const char __c[] PROGMEM_I1 = "\xff\xff" s; &__c[0];}))
|
||||
#define ISTR(s) "\xff\xff" s
|
||||
#define _i(s) lang_get_translation(_I(s))
|
||||
#define _T(s) lang_get_translation(s)
|
||||
```
|
||||
That explains the macros:
|
||||
- `_i` expands into `lang_get_translation((__extension__({static const char __c[] PROGMEM_I1 = "\xff\xff" s; &__c[0];})))` . Note the two 0xff's in the beginning of the string. `_i` allows for declaring a string directly inplace of C++ code, no string table is used. The downside of this approach is obvious - the compiler is not able/willing to merge duplicit strings into one.
|
||||
- `_T` expands into `lang_get_translation(s)` without the two 0xff's at the beginning. Must be used in conjunction with MSG tables in `messages.h`. Allows to declare a string only once and use many times.
|
||||
- `_N` means not-translated. These strings reside in a different segment of memory.
|
||||
|
||||
The two 0xff's are somehow magically replaced by real string ID's where the translations are available (still don't know where).
|
||||
```C++
|
||||
const char* lang_get_translation(const char* s){
|
||||
if (lang_selected == 0) return s + 2; //primary language selected, return orig. str.
|
||||
if (lang_table == 0) return s + 2; //sec. lang table not found, return orig. str.
|
||||
uint16_t ui = pgm_read_word(((uint16_t*)s)); //read string id
|
||||
if (ui == 0xffff) return s + 2; //translation not found, return orig. str.
|
||||
ui = pgm_read_word(((uint16_t*)(((char*)lang_table + 16 + ui*2)))); //read relative offset
|
||||
if (pgm_read_byte(((uint8_t*)((char*)lang_table + ui))) == 0) //read first character
|
||||
return s + 2;//zero length string == not translated, return orig. str.
|
||||
return (const char*)((char*)lang_table + ui); //return calculated pointer
|
||||
}
|
||||
```
|
||||
|
||||
## Files
|
||||
|
||||
### `lang_en.txt`
|
||||
```
|
||||
#MSG_CRASH_DET_ONLY_IN_NORMAL c=20 r=4
|
||||
"Crash detection can\x0abe turned on only in\x0aNormal mode"
|
||||
```
|
||||
|
||||
### `lang_en_*.txt`
|
||||
```
|
||||
#MSG_CRASH_DET_ONLY_IN_NORMAL c=20 r=4
|
||||
"Crash detection can\x0abe turned on only in\x0aNormal mode"
|
||||
"Crash detekce muze\x0abyt zapnuta pouze v\x0aNormal modu"
|
||||
```
|
||||
1. a comment - usually a MSG define with number of characters (c) and rows (r)
|
||||
2. English text
|
||||
3. translated text
|
||||
|
||||
### `not_tran.txt`
|
||||
A simple list of strings that are not translated yet.
|
||||
|
||||
### `not_used.txt`
|
||||
A list os strings not currently used in this variant of the firmware or are obsolete.
|
||||
Example: There are MK2.5 specific messages that aren't used when you compile a MK3 variant and vice versa. So be carefull and double check the code if this message is obsolete or just not used due to the chosen variant.
|
||||
|
||||
## Scripts
|
||||
|
||||
### `config.sh`
|
||||
- Checks setup and sets auxiliary env vars used in many other scripts.
|
||||
- Looks for env var `ARDUINO`. If not found/empty, a default `C:/arduino-1.8.5` is used.
|
||||
- Sets env var `CONFIG_OK=1` when all good, otherwise sets `CONFIG_OK=0`
|
||||
|
||||
### `fw-build.sh`
|
||||
Joins firmware HEX and language binaries into one file.
|
||||
|
||||
### `fw-clean.sh`
|
||||
|
||||
### `lang-add.sh`
|
||||
Adds new messages into the dictionary regardless of whether there have been any older versions.
|
||||
|
||||
### `lang-build.sh`
|
||||
Generates lang_xx.bin (language binary files) for the whole firmware build.
|
||||
|
||||
Arguments:
|
||||
- `$1` : language code (`en`, `cz`, `de`, `es`, `fr`, `it`, `pl`) or `all`
|
||||
- empty/no arguments defaults to `all`
|
||||
|
||||
Input: `lang_en.txt` or `lang_en_xx.txt`
|
||||
|
||||
Output: `lang_xx.bin`
|
||||
|
||||
Temporary files: `lang_xx.tmp` and `lang_xx.dat`
|
||||
|
||||
Description of the process:
|
||||
The script first runs `lang-check.py $1` and removes empty lines and comments (and non-translated texts) into `lang_$1.tmp`.
|
||||
The tmp file now contains all translated texts (some of them empty, i.e. "").
|
||||
The tmp file is then transformed into `lang_$1.dat`, which is a simple dump of all texts together, each terminated with a `\x00`.
|
||||
Format of the `bin` file:
|
||||
- 00-01: `A5 5A`
|
||||
- 02-03: `B4 4B`
|
||||
- 04-05: 2B size
|
||||
- 06-07: 2B number of strings
|
||||
- 08-09: 2B checksum
|
||||
- 0A-0B: 2B lang code hex data: basically `en` converted into `ne`, i.e. characters swapped. Only `cz` is changed into `sc` (old `cs` ISO code).
|
||||
- 0C-0D: 2B signature low
|
||||
- 0E-0F: 2B signature high
|
||||
- 10-(10 + 2*number of strings): table of string offsets from the beginning of this file
|
||||
- after the table there are the strings themselves, each terminated with `\x00`
|
||||
|
||||
The signature is composed of 2B number of strings and 2B checksum in lang_en.bin. Signature in lang_en.bin is zero.
|
||||
|
||||
### `lang-check.sh` and `lang-check.py`
|
||||
Both do the same, only lang-check.py is newer, i.e. lang-check.sh is not used anymore.
|
||||
lang-check.py makes a binary comparison between what's in the dictionary and what's in the binary.
|
||||
|
||||
### `lang-clean.sh`
|
||||
Removes all language output files from lang folder. That means deleting:
|
||||
- if [ "$1" = "en" ]; then
|
||||
rm_if_exists lang_$1.tmp
|
||||
else
|
||||
rm_if_exists lang_$1.tmp
|
||||
rm_if_exists lang_en_$1.tmp
|
||||
rm_if_exists lang_en_$1.dif
|
||||
rm_if_exists lang_$1.ofs
|
||||
rm_if_exists lang_$1.txt
|
||||
fi
|
||||
rm_if_exists lang_$1_check.dif
|
||||
rm_if_exists lang_$1.bin
|
||||
rm_if_exists lang_$1.dat
|
||||
rm_if_exists lang_$1_1.tmp
|
||||
rm_if_exists lang_$1_2.tmp
|
||||
|
||||
### `lang-export.sh`
|
||||
Exports PO (gettext) for external translators.
|
||||
|
||||
### `lang-import.sh`
|
||||
Import from PO.
|
||||
|
||||
Arguments:
|
||||
- `$1` : language code (`en`, `cz`, `de`, `es`, `fr`, `it`, `pl`)
|
||||
- empty/no arguments quits the script
|
||||
|
||||
Input files: `<language code>.po` files like `de.po`, `es.po`, etc.
|
||||
|
||||
Input folder: ´/lang/po/new´
|
||||
|
||||
Output files:
|
||||
|
||||
Output foler: ´/lang/po/new´
|
||||
|
||||
Needed improments to scrpit:
|
||||
- add `all` argument
|
||||
- update `replace in <language> translations` to all known special characters the LCD display with Japanese ROM cannot display
|
||||
- move `lang_en_<language code>.txt` to folder `/lang`
|
||||
- cleanup `<language code>_filtered.po`, `<language code>_new.po` and `nonasci.txt`
|
||||
|
||||
### `progmem.sh`
|
||||
|
||||
Examine content of progmem sections (default is progmem1).
|
||||
|
||||
Input:
|
||||
- $OUTDIR/Firmware.ino.elf
|
||||
- $OUTDIR/sketch/*.o (all object files)
|
||||
|
||||
Outputs:
|
||||
- text.sym - formated symbol listing of section '.text'
|
||||
- $PROGMEM.sym - formated symbol listing of section '.progmemX'
|
||||
- $PROGMEM.lss - disassembly listing file
|
||||
- $PROGMEM.hex - variables - hex
|
||||
- $PROGMEM.chr - variables - char escape
|
||||
- $PROGMEM.var - variables - strings
|
||||
- $PROGMEM.txt - text data only (not used)
|
||||
|
||||
Description of process:
|
||||
- check input files
|
||||
- remove output files
|
||||
- list symbol table of section '.text' from output elf file to text.sym (sorted by address)
|
||||
- calculate start and stop address of section '.$PROGMEM'
|
||||
- dump $PROGMEM data in hex format, cut disassembly (keep hex data only) into $PROGMEM.lss
|
||||
- convert $PROGMEM.lss to $PROGMEM.hex:
|
||||
- replace empty lines with '|' (variables separated by empty lines)
|
||||
- remove address from multiline variables (keep address at first variable line only)
|
||||
- remove '<' and '>:', remove whitespace at end of lines
|
||||
- remove line-endings, replace separator with '\n' (join hex data lines - each line will contain single variable)
|
||||
- convert $PROGMEM.hex to $PROGMEM.chr (prepare string data for character check and conversion)
|
||||
- replace first space with tab
|
||||
- replace second and third space with tab and space
|
||||
- replace all remaining spaces with '\x'
|
||||
- replace all tabs with spaces
|
||||
- convert $PROGMEM.chr to $PROGMEM.var (convert data to text) - a set of special characters is escaped here including `\x0a`
|
||||
|
||||
|
||||
### `textaddr.sh`
|
||||
|
||||
Compiles `progmem1.var` and `lang_en.txt` files to `textaddr.txt` file (mapping of progmem addreses to text idenifiers).
|
||||
|
||||
Description of process:
|
||||
- check if input files exists
|
||||
- create sorted list of strings from progmem1.var and lang_en.txt
|
||||
- lines from progmem1.var will contain addres (8 chars) and english text
|
||||
- lines from lang_en.txt will contain linenumber and english text
|
||||
- after sort this will generate pairs of lines (line from progmem1 first)
|
||||
- result of sort is compiled with simple script and stored into file textaddr.txt
|
||||
|
||||
Input:
|
||||
- progmem1.var
|
||||
- lang_en.txt
|
||||
|
||||
Output:
|
||||
- textaddr.txt
|
||||
|
||||
|
||||
|
||||
update_lang.sh
|
78
lang/update_lang.sh
Normal file
78
lang/update_lang.sh
Normal file
|
@ -0,0 +1,78 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# update_lang.sh - multi-language support script
|
||||
# Update secondary language in binary file.
|
||||
#
|
||||
# Config:
|
||||
if [ -z "$CONFIG_OK" ]; then eval "$(cat config.sh)"; fi
|
||||
if [ -z "$OBJCOPY" ]; then echo 'variable OBJCOPY not set!' >&2; exit 1; fi
|
||||
if [ -z "$CONFIG_OK" ] | [ $CONFIG_OK -eq 0 ]; then echo 'Config NG!' >&2; exit 1; fi
|
||||
#
|
||||
# Selected language:
|
||||
LNG=$1
|
||||
if [ -z "$LNG" ]; then LNG='cz'; fi
|
||||
#
|
||||
|
||||
finish()
|
||||
{
|
||||
echo
|
||||
if [ "$1" = "0" ]; then
|
||||
echo "update_lang.sh finished with success" >&2
|
||||
else
|
||||
echo "update_lang.sh finished with errors!" >&2
|
||||
fi
|
||||
case "$-" in
|
||||
*i*) echo "press enter key" >&2; read ;;
|
||||
esac
|
||||
exit $1
|
||||
}
|
||||
|
||||
echo "update_lang.sh started" >&2
|
||||
echo " selected language=$LNG" >&2
|
||||
|
||||
echo -n " checking files..." >&2
|
||||
if [ ! -e text.sym ]; then echo "NG! file text.sym not found!" >&2; finish 1; fi
|
||||
if [ ! -e lang_$LNG.bin ]; then echo "NG! file lang_$LNG.bin not found!" >&2; finish 1; fi
|
||||
if [ ! -e firmware.bin ]; then echo "NG! file firmware.bin not found!" >&2; finish 1; fi
|
||||
echo "OK" >&2
|
||||
|
||||
echo -n " checking symbols..." >&2
|
||||
#find symbol _SEC_LANG in section '.text'
|
||||
sec_lang=$(cat text.sym | grep -E "\b_SEC_LANG\b")
|
||||
if [ -z "$sec_lang" ]; then echo "NG!\n symbol _SEC_LANG not found!" >&2; finish 1; fi
|
||||
#find symbol _PRI_LANG_SIGNATURE in section '.text'
|
||||
pri_lang=$(cat text.sym | grep -E "\b_PRI_LANG_SIGNATURE\b")
|
||||
if [ -z "$pri_lang" ]; then echo "NG!\n symbol _PRI_LANG_SIGNATURE not found!" >&2; finish 1; fi
|
||||
echo "OK" >&2
|
||||
|
||||
echo " calculating vars:" >&2
|
||||
#get pri_lang addres
|
||||
pri_lang_addr='0x'$(echo $pri_lang | cut -f1 -d' ')
|
||||
echo " pri_lang_addr =$pri_lang_addr" >&2
|
||||
#get addres and size
|
||||
sec_lang_addr='0x'$(echo $sec_lang | cut -f1 -d' ')
|
||||
sec_lang_size='0x'$(echo $sec_lang | cut -f2 -d' ')
|
||||
echo " sec_lang_addr =$sec_lang_addr" >&2
|
||||
echo " sec_lang_size =$sec_lang_size" >&2
|
||||
#calculate lang_table_addr (aligned to 256byte page)
|
||||
lang_table_addr=$((256*$((($sec_lang_addr + 255) / 256))))
|
||||
printf " lang_table_addr =0x%04x\n" $lang_table_addr >&2
|
||||
#calculate lang_table_size
|
||||
lang_table_size=$((256*$((($sec_lang_size - ($lang_table_addr - $sec_lang_addr))/256))))
|
||||
printf " lang_table_size =0x%04x (=%d bytes)\n" $lang_table_size $lang_table_size >&2
|
||||
|
||||
#get lang_xx.bin file size
|
||||
lang_file_size=$(wc -c lang_$LNG.bin | cut -f1 -d' ')
|
||||
printf " lang_file_size =0x%04x (=%d bytes)\n" $lang_file_size $lang_file_size >&2
|
||||
|
||||
if [ $lang_file_size -gt $lang_table_size ]; then echo "Lanaguage binary file size too big!" >&2; finish 1; fi
|
||||
|
||||
echo "updating 'firmware.bin'..." >&2
|
||||
|
||||
dd if=lang_$LNG.bin of=firmware.bin bs=1 seek=$lang_table_addr conv=notrunc 2>/dev/null
|
||||
|
||||
#convert bin to hex
|
||||
echo "converting to hex..." >&2
|
||||
$OBJCOPY -I binary -O ihex ./firmware.bin ./firmware_$LNG.hex
|
||||
|
||||
finish 0
|
Loading…
Add table
Add a link
Reference in a new issue