1
0
Fork 0

locale: Improve handling of non-ASCII characters (fix #469)

master
Gordon Williams 2020-06-01 17:04:55 +01:00
parent 30ae2f65f5
commit d9442f2fd0
4 changed files with 103 additions and 21 deletions

View File

@ -65,7 +65,7 @@
{ "id": "locale",
"name": "Languages",
"icon": "locale.png",
"version":"0.06",
"version":"0.07",
"description": "Translations for different countries",
"tags": "tool,system,locale,translate",
"type": "locale",

View File

@ -6,3 +6,4 @@
Add correct scaling for speed/distance/temperature
0.06: Remove translations if not required
Ensure 'on' is always supplied for translations
0.07: Improve handling of non-ASCII characters (fix #469)

View File

@ -1,5 +1,6 @@
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="../../css/spectre.min.css">
</head>
<body>
@ -12,7 +13,7 @@
<p>Then click <button id="upload" class="btn btn-primary">Upload</button></p>
<script src="../../lib/customize.js"></script>
<script src="locales.js"></script>
<script src="locales.js" charset="utf-8"></script>
<script>
/*
@ -45,7 +46,23 @@ exports = { name : "en_GB", currencySym:"£",
};
*/
function codePageLookup(lang, codePage, ch) {
var chCode = ch.charCodeAt();
if (chCode>=32 && chCode<128) return ch; // ASCII - copy it
// not normal ASCII
var n; // default is a space
if (codePage.map.indexOf(ch)>=0) // look up in char map, escape that
n = 128+codePage.map.indexOf(ch);
/*else if (chCode<256) // it's non-ascii, but <256 - just escape it
n = chCode;*/
else {
if (charFallbacks[ch]) return charFallbacks[ch];
console.error(`Locale ${lang}: Character ${ch} (${chCode}) is not in Code Page ${codePage.name}`);
return undefined;
}
// escape the char
return '\\x'+(n+256).toString(16).substr(-2);
}
// do some sanity checks
Object.keys(locales).forEach(function(localeName) {
@ -54,6 +71,22 @@ exports = { name : "en_GB", currencySym:"£",
if (distanceUnits[locale.distance[0]]===undefined) console.error(localeName+": Unknown distance unit "+locale.distance[0]);
if (distanceUnits[locale.distance[1]]===undefined) console.error(localeName+": Unknown distance unit "+locale.distance[1]);
if (speedUnits[locale.speed]===undefined) console.error(localeName+": Unknown speed unit "+locale.speed);
if (locale.temperature!='°C' && locale.temperature!='°F')
console.error(localeName+": Unknown temperature unit "+locale.temperature);
// Now check that codepage is ok and all chars in translation are in that codepage
const codePageName = "ISO8859-1";
if (locale.codePage) codePageName = locale.codePage;
const codePage = codePages[codePageName];
if (codePage===undefined) console.error(localeName+": Unknown codePage "+codePageName);
function checkChars(v,path) {
if ("object"==typeof v)
Object.keys(v).forEach(k=>checkChars(v[k], path+"."+k));
else if ("string"==typeof v)
for (var i=0;i<v.length;i++)
if (codePageLookup(localeName, codePage, v[i])===undefined)
console.error(` ... in ${path}[${i}]`);
}
checkChars(locale,localeName);
});
var languageSelector = document.getElementById("languages");
@ -68,17 +101,37 @@ exports = { name : "en_GB", currencySym:"£",
document.getElementById("upload").addEventListener("click", function() {
var lang = languageSelector.options[languageSelector.selectedIndex].value;
console.log(lang);
const lang = languageSelector.options[languageSelector.selectedIndex].value;
console.log(`Language ${lang}`);
locale = locales[lang];
const locale = locales[lang];
if (!locale) {
alert("Language not found!");
alert(`Language ${lang} not found!`);
return;
}
const codePageName = "ISO8859-1";
if (locale.codePage)
codePageName = locale.codePage;
const codePage = codePages[codePageName];
if (!codePage) {
alert(`Code Page ${codePageName} not found!`);
return;
}
function js(x) { return JSON.stringify(x); }
// Convert object to JSON, with codepage
function js(x) {
// do nortmal conversion
x = JSON.stringify(x);
/* assume any out of bounds character is going to
be inside a quoted string */
var s = '';
for (var i=0;i<x.length;i++) {
var ch = codePageLookup(lang, codePage, x[i]);
s += (ch===undefined) ? "?" : ch;
}
return s;
}
var replaceList = {
"%Y": "d.getFullYear()",
@ -116,7 +169,7 @@ exports = { name : "en_GB", currencySym:"£",
else if (locale.temperature=='°F') temperature="(t*9/5)+32";
else throw new Error("Unknown temperature unit "+locale.temperature);
var localeModule = `var l = ${JSON.stringify({
var localeModule = `var l = ${js({
abday : locale.abday,
day : locale.day,
abmonth : locale.abmonth,

View File

@ -13,6 +13,34 @@ const speedUnits = { // how many kph per X?
"mph": 1.60934
};
/*
For a codepage, 'map' is a map of char codes 128 and above.
Where there is no character, just use '.'
*/
const codePages = {
"ISO8859-1" : {
name : "ISO8859-1",
map : `
.ƒˆŠŒ.Ž.
.˜šœ.žŸ
.¡¢£¤¥¦§¨©ª«¬.®¯
°±²³´µ·¸¹º»¼½¾¿
ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ
ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß
àáâãäåæçèéêëìíîï
ðñòóôõö÷øùúûüýþÿ
`.replace(/[ \n]/g,"")
}
};
/* When it's not in the codepage, try and use
these conversions */
const charFallbacks = {
"č":"c",
"ř":"r",
"ő":"o",
"ě":"e"
};
/*
timePattern / datePattern:
@ -56,7 +84,7 @@ var locales = {
lang: "de_DE",
decimal_point: ",",
thousands_sep: ".",
currency_symbol: "\x80",
currency_symbol: "",
int_curr_symbol: "EUR",
speed: "kmh",
distance: { 0: "m", 1: "km" },
@ -92,7 +120,7 @@ var locales = {
lang: "en_JP",
decimal_point: ".",
thousands_sep: ",",
currency_symbol: "",
currency_symbol: "¥",
int_curr_symbol: "JPY",
speed: "kmh",
distance: { 0: "m", 1: "km" },
@ -110,7 +138,7 @@ var locales = {
lang: "nl_NL",
decimal_point: ",",
thousands_sep: ".",
currency_symbol: "\x80",
currency_symbol: "",
int_curr_symbol: "EUR",
speed: "kmh",
distance: { 0: "m", 1: "km" },
@ -146,7 +174,7 @@ var locales = {
lang: "fr_FR",
decimal_point: ",",
thousands_sep: " ",
currency_symbol: "\x80",
currency_symbol: "",
int_curr_symbol: "EUR",
speed: "km/h",
distance: { 0: "m", 1: "km" },
@ -200,7 +228,7 @@ var locales = {
lang: "de_AT",
decimal_point: ",",
thousands_sep: ".",
currency_symbol: "\x80",
currency_symbol: "",
int_curr_symbol: "EUR",
speed: "kmh",
distance: { 0: "m", 1: "km" },
@ -217,7 +245,7 @@ var locales = {
lang: "en_IL",
decimal_point: ",",
thousands_sep: ".",
currency_symbol: "₪",
currency_symbol: "ILS"/*"₪"*/,
int_curr_symbol: "ILS",
speed: "kmh",
distance: { 0: "m", 1: "km" },
@ -235,7 +263,7 @@ var locales = {
lang: "es_ES",
decimal_point: ",",
thousands_sep: ".",
currency_symbol: "\x80",
currency_symbol: "",
int_curr_symbol: "EUR",
speed: "kmh",
distance: { 0: "m", 1: "km" },
@ -253,7 +281,7 @@ var locales = {
lang: "fr_BE",
decimal_point: ",",
thousands_sep: ".",
currency_symbol: "\x80",
currency_symbol: "",
int_curr_symbol: "EUR",
speed: "kmh",
distance: { 0: "m", 1: "km" },
@ -271,7 +299,7 @@ var locales = {
lang: "fi_FI",
decimal_point: ",",
thousands_sep: ".",
currency_symbol: "\x80",
currency_symbol: "",
int_curr_symbol: "EUR",
speed: "kmh",
distance: { 0: "m", 1: "km" },
@ -343,7 +371,7 @@ var locales = {
lang: "it_IT",
decimal_point: ",",
thousands_sep: ".",
currency_symbol: "\x80",
currency_symbol: "",
int_curr_symbol: "EUR",
speed: 'kmh',
distance: { "0": "m", "1": "km" },
@ -429,7 +457,7 @@ var locales = {
day: "Domingo,Segunda-feira,Terça-feira,Quarta-feira,Quinta-feira,Sexta-feira,Sábado",
trans: { yes: "sim", Yes: "Sim", no: "não", No: "Não", ok: "certo", on: "ligado", off: "desligado" }
},
"cs_CZ": {
"cs_CZ": { // THIS NEVER WORKED PROPERLY - many chars are not in the ISO8859-1 codepage and we use charFallbacks
lang: "cs_CZ",
decimal_point: ",",
thousands_sep: " ",
@ -451,7 +479,7 @@ var locales = {
lang: "sl_SI",
decimal_point: ",",
thousands_sep: ".",
currency_symbol: "\x80",
currency_symbol: "",
int_curr_symbol: "EUR",
speed: "km/h",
distance: { 0: "m", 1: "km" },