Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Docassemble translates anything that reaches Python through `word()`, but JavaSc
running in the browser has no way to reach that catalog, so strings in custom datatypes
and small widgets tend to stay hardcoded in English.

ALToolbox adds an endpoint, `/al_translations.json?lang=es`, that returns the `word()`
ALToolbox adds an endpoint, `/al_translations.json?lang=es`, that returns the `word()`
catalog for a language, and a script that puts it behind `_()`:

```yaml
Expand Down
5 changes: 4 additions & 1 deletion docassemble/ALToolbox/PhoneNumberDataType.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,13 @@ class PhoneNumber(CustomDataType):
* @returns {string} - Message to show if the field is invalid
*/
function showInvalidInputMessage( params, field ) {
var defaultMessage = `This phone number doesn't look right. Note that a non-US number needs a "+" before the number.`;
return (
$(field).attr('data-alInvalidInputMessage')
// The default message could be confusing for invalid US phone numbers
|| `This phone number doesn't look right. Note that a non-US number needs a "+" before the number.`
|| (typeof window.alTranslate === 'function'
? window.alTranslate(defaultMessage)
: defaultMessage)
)
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ comment: |
features:
javascript:
- "https://cdn.jsdelivr.net/npm/intl-tel-input@25.12.5/build/js/intlTelInput.min.js"
- al_translate.js
- phone-number-validation.js
css:
- "https://cdn.jsdelivr.net/npm/intl-tel-input@25.12.5/build/css/intlTelInput.min.css"
Expand All @@ -21,3 +22,4 @@ features:
---
modules:
- .PhoneNumberDataType
- .translation_strings
150 changes: 145 additions & 5 deletions docassemble/ALToolbox/data/sources/altoolbox_words.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,149 @@
# words:
# - docassemble.ALToolbox:data/sources/altoolbox_words.yml
#
# The same format works for your own strings. Copy this file into your package's
# data/sources directory, add your languages and phrases, and list it under
# `words:` alongside this one.
# AssemblyLine includes these entries in its standard word catalogs. This file
# remains a fallback for servers that use ALToolbox without AssemblyLine.
ar:
"Change country, selected ${countryName} (${dialCode})": "تغيير البلد، المحدد حاليًا ${countryName} (${dialCode})"
"Select country": "حدد الدولة"
"List of countries": "قائمة الدول"
"Search": "يبحث"
"Clear search": "مسح البحث"
"No results found": "لم يتم العثور على نتائج"
"1 result found": "تم العثور على نتيجة واحدة"
"${count} results found": "تم العثور على ${count} نتيجة"
'This phone number doesn''t look right. Note that a non-US number needs a "+" before the number.': 'يبدو أن رقم الهاتف هذا غير صحيح. لاحظ أن الرقم غير الأمريكي يحتاج إلى "+" قبل الرقم.'
"You have entered %d character.": "لقد أدخلت %d حرفًا."
"You have entered %d characters.": "لقد أدخلت %d أحرف."
es:
You have entered %d character.: Ha escrito %d carácter.
You have entered %d characters.: Ha escrito %d caracteres.
"Change country, selected ${countryName} (${dialCode})": "Cambiar país, seleccionado ${countryName} (${dialCode})"
"Select country": "Seleccionar país"
"List of countries": "Lista de países"
"Search": "Buscar"
"Clear search": "Borrar búsqueda"
"No results found": "No se han encontrado resultados"
"1 result found": "1 resultado encontrado"
"${count} results found": "Se encontraron ${count} resultados"
'This phone number doesn''t look right. Note that a non-US number needs a "+" before the number.': 'Este número de teléfono no parece correcto. Tenga en cuenta que un número que no es de EE. UU. necesita un "+" antes del número.'
"You have entered %d character.": "Ha escrito %d carácter."
"You have entered %d characters.": "Ha escrito %d caracteres."
fr:
"Change country, selected ${countryName} (${dialCode})": "Changer de pays, ${countryName} sélectionné (${dialCode})"
"Select country": "Sélectionner un pays"
"List of countries": "Liste des pays"
"Search": "Recherche"
"Clear search": "Effacer la recherche"
"No results found": "Aucun résultat trouvé"
"1 result found": "1 résultat trouvé"
"${count} results found": "${count} résultats trouvés"
'This phone number doesn''t look right. Note that a non-US number needs a "+" before the number.': 'Ce numéro de téléphone ne semble pas correct. Notez qu’un numéro non américain doit être précédé d’un "+".'
"You have entered %d character.": "Vous avez saisi %d caractère."
"You have entered %d characters.": "Vous avez saisi %d caractères."
ht:
"Change country, selected ${countryName} (${dialCode})": "Chanje peyi, peyi chwazi ${countryName} (${dialCode})"
"Select country": "Chwazi peyi"
"List of countries": "Lis peyi yo"
"Search": "Rechèch"
"Clear search": "Efase rechèch"
"No results found": "Pa jwenn okenn rezilta"
"1 result found": "Yo jwenn 1 rezilta"
"${count} results found": "Yo jwenn ${count} rezilta"
'This phone number doesn''t look right. Note that a non-US number needs a "+" before the number.': 'Nimewo telefòn sa a pa sanble kòrèk. Tanpri sonje yon nimewo ki pa ameriken bezwen yon "+" anvan nimewo a.'
"You have entered %d character.": "Ou antre %d karaktè."
"You have entered %d characters.": "Ou antre %d karaktè."
km:
"Change country, selected ${countryName} (${dialCode})": "ប្តូរប្រទេស ប្រទេសដែលបានជ្រើសរើស ${countryName} (${dialCode})"
"Select country": "ជ្រើសរើសប្រទេស"
"List of countries": "បញ្ជីប្រទេស"
"Search": "ស្វែងរក"
"Clear search": "សម្អាតការស្វែងរក"
"No results found": "រកមិនឃើញលទ្ធផល"
"1 result found": "រកឃើញលទ្ធផល ១"
"${count} results found": "រកឃើញលទ្ធផល ${count}"
'This phone number doesn''t look right. Note that a non-US number needs a "+" before the number.': 'លេខទូរសព្ទនេះមើលទៅមិនត្រឹមត្រូវទេ។ សូមចំណាំថា លេខទូរសព្ទដែលមិនមែនជាលេខអាមេរិក ត្រូវដាក់សញ្ញា "+" នៅពីមុខលេខ។'
"You have entered %d character.": "អ្នកបានបញ្ចូល %d តួអក្សរ។"
"You have entered %d characters.": "អ្នកបានបញ្ចូល %d តួអក្សរ។"
pt:
"Change country, selected ${countryName} (${dialCode})": "Alterar país, país selecionado ${countryName} (${dialCode})"
"Select country": "Selecionar país"
"List of countries": "Lista de países"
"Search": "Procurar"
"Clear search": "Limpar pesquisa"
"No results found": "Nenhum resultado encontrado"
"1 result found": "1 resultado encontrado"
"${count} results found": "${count} resultados encontrados"
'This phone number doesn''t look right. Note that a non-US number needs a "+" before the number.': 'Este número de telefone não parece correto. Observe que um número que não seja dos EUA precisa de um "+" antes do número.'
"You have entered %d character.": "Você digitou %d caractere."
"You have entered %d characters.": "Você digitou %d caracteres."
vi:
"Change country, selected ${countryName} (${dialCode})": "Đổi quốc gia, quốc gia đã chọn ${countryName} (${dialCode})"
"Select country": "Chọn quốc gia"
"List of countries": "Danh sách các quốc gia"
"Search": "Tìm kiếm"
"Clear search": "Xóa tìm kiếm"
"No results found": "Không tìm thấy kết quả nào"
"1 result found": "Đã tìm thấy 1 kết quả"
"${count} results found": "Đã tìm thấy ${count} kết quả"
'This phone number doesn''t look right. Note that a non-US number needs a "+" before the number.': 'Số điện thoại này có vẻ không đúng. Lưu ý rằng số điện thoại không phải của Hoa Kỳ cần có dấu "+" trước số.'
"You have entered %d character.": "Bạn đã nhập %d ký tự."
"You have entered %d characters.": "Bạn đã nhập %d ký tự."
zh-Hans:
"Change country, selected ${countryName} (${dialCode})": "更改国家/地区,当前选定的国家/地区为 ${countryName} (${dialCode})"
"Select country": "选择国家/地区"
"List of countries": "国家/地区列表"
"Search": "搜索"
"Clear search": "清除搜索"
"No results found": "未找到结果"
"1 result found": "找到 1 个结果"
"${count} results found": "找到 ${count} 个结果"
'This phone number doesn''t look right. Note that a non-US number needs a "+" before the number.': '此电话号码似乎不正确。请注意,非美国电话号码需要在号码前加上“+”。'
"You have entered %d character.": "您已输入 %d 个字符。"
"You have entered %d characters.": "您已输入 %d 个字符。"
zh-CN:
"Change country, selected ${countryName} (${dialCode})": "更改国家/地区,当前选定的国家/地区为 ${countryName} (${dialCode})"
"Select country": "选择国家/地区"
"List of countries": "国家/地区列表"
"Search": "搜索"
"Clear search": "清除搜索"
"No results found": "未找到结果"
"1 result found": "找到 1 个结果"
"${count} results found": "找到 ${count} 个结果"
'This phone number doesn''t look right. Note that a non-US number needs a "+" before the number.': '此电话号码似乎不正确。请注意,非美国电话号码需要在号码前加上“+”。'
"You have entered %d character.": "您已输入 %d 个字符。"
"You have entered %d characters.": "您已输入 %d 个字符。"
zh-Hant:
"Change country, selected ${countryName} (${dialCode})": "更改國家/地區,目前選擇的國家/地區為 ${countryName} (${dialCode})"
"Select country": "選擇國家/地區"
"List of countries": "國家/地區清單"
"Search": "搜尋"
"Clear search": "清除搜尋"
"No results found": "找不到結果"
"1 result found": "找到 1 個結果"
"${count} results found": "找到 ${count} 個結果"
'This phone number doesn''t look right. Note that a non-US number needs a "+" before the number.': '此電話號碼似乎不正確。請注意,非美國電話號碼需要在號碼前加上「+」。'
"You have entered %d character.": "您已輸入 %d 個字元。"
"You have entered %d characters.": "您已輸入 %d 個字元。"
zh-TW:
"Change country, selected ${countryName} (${dialCode})": "更改國家/地區,目前選擇的國家/地區為 ${countryName} (${dialCode})"
"Select country": "選擇國家/地區"
"List of countries": "國家/地區清單"
"Search": "搜尋"
"Clear search": "清除搜尋"
"No results found": "找不到結果"
"1 result found": "找到 1 個結果"
"${count} results found": "找到 ${count} 個結果"
'This phone number doesn''t look right. Note that a non-US number needs a "+" before the number.': '此電話號碼似乎不正確。請注意,非美國電話號碼需要在號碼前加上「+」。'
"You have entered %d character.": "您已輸入 %d 個字元。"
"You have entered %d characters.": "您已輸入 %d 個字元。"
ne:
"Change country, selected ${countryName} (${dialCode})": "देश परिवर्तन गर्नुहोस्, हाल चयन गरिएको ${countryName} (${dialCode})"
"Select country": "देश चयन गर्नुहोस्"
"List of countries": "देशहरूको सूची"
"Search": "खोज्नुहोस्"
"Clear search": "खोजी खाली गर्नुहोस्"
"No results found": "कुनै परिणाम फेला परेन"
"1 result found": "१ परिणाम फेला पर्यो"
"${count} results found": "${count} वटा परिणाम फेला परे"
'This phone number doesn''t look right. Note that a non-US number needs a "+" before the number.': 'यो फोन नम्बर सही जस्तो देखिँदैन। अमेरिकाबाहिरको नम्बरअघि "+" राख्नुपर्छ भन्ने कुरा ध्यान दिनुहोस्।'
"You have entered %d character.": "तपाईंले %d अक्षर प्रविष्ट गर्नुभएको छ।"
"You have entered %d characters.": "तपाईंले %d अक्षरहरू प्रविष्ट गर्नुभएको छ।"
91 changes: 81 additions & 10 deletions docassemble/ALToolbox/data/static/phone-number-validation.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,66 @@
$(document).on('daPageLoad', function(){
(function () {
function currentLanguage() {
return (
window.alTranslationsLang ||
document.documentElement.getAttribute("lang") ||
"en"
);
}

function translate(text) {
return typeof window.alTranslate === "function"
? window.alTranslate(text)
: text;
}

function getUiTranslations() {
return {
selectedCountryAriaLabel: translate(
"Change country, selected ${countryName} (${dialCode})"
),
noCountrySelected: translate("Select country"),
countryListAriaLabel: translate("List of countries"),
searchPlaceholder: translate("Search"),
clearSearchAriaLabel: translate("Clear search"),
zeroSearchResults: translate("No results found"),
oneSearchResult: translate("1 result found"),
multipleSearchResults: translate("${count} results found"),
};
}

function getI18n() {
var translations = getUiTranslations();
if (
typeof Intl === "undefined" ||
typeof Intl.DisplayNames !== "function" ||
!window.intlTelInput.getCountryData
) {
return translations;
}

try {
var regionNames = new Intl.DisplayNames(
[currentLanguage().replace(/_/g, "-")],
{ type: "region" }
);
window.intlTelInput.getCountryData().forEach(function (country) {
try {
var name = regionNames.of(country.iso2.toUpperCase());
if (name) {
translations[country.iso2] = name;
}
} catch (error) {
// A private-use or otherwise unknown country code can be skipped.
}
});
} catch (error) {
// If the browser has no country names for this locale, keep the
// translated interface and let intl-tel-input use its English names.
}
return translations;
}

function setupPhoneInputs() {
/** When the page first loads, gets the value from any `.al_international_phone` input
* field, transforms it, puts the transformed value back into the input
* field, and adds a dropdown from which to choose a country. It
Expand Down Expand Up @@ -30,20 +92,26 @@ $(document).on('daPageLoad', function(){
* 1. https://github.com/google/libphonenumber/blob/master/FAQ.md
*/

// Loop through all the .al_international_phone input fields on the current screen
let phoneNodes = document.querySelectorAll( '.al_international_phone' ); // Class given by the CustomDataType
for ( var node of phoneNodes ) {
var telObj = window.intlTelInput( node, {
// Loop through all the .al_international_phone input fields on the current screen
let phoneNodes = document.querySelectorAll( '.al_international_phone' ); // Class given by the CustomDataType
for ( var node of phoneNodes ) {
if (node._alToolboxPhoneInstance) {
node._alToolboxPhoneInstance.destroy();
}

var telObj = window.intlTelInput( node, {
// The default country without any input into the plugin is 'us'
// Once the user puts in the phone number of another country, though,
// it will remember that country
initialCountry: 'us',
i18n: getI18n(),
loadUtils: () => import("https://cdn.jsdelivr.net/npm/intl-tel-input@25.12.5/build/js/utils.js"),
autoPlaceholder: "off",
formatAsYouType: false,
// Avoid default of MOBILE (https://github.com/jackocnr/intl-tel-input?tab=readme-ov-file#:~:text=validationNumberTypes,-Type%3A%20String)
validationNumberTypes: null,
});
});
node._alToolboxPhoneInstance = telObj;

// If the user already entered a number and comes back to the page,
// docassemble puts the previously saved value into the input field.
Expand All @@ -52,7 +120,10 @@ $(document).on('daPageLoad', function(){
// can see it if you go forward and back three times on our demo screens.

// See https://www.npmjs.com/package/intl-tel-input#recommended-usage about the full international format.
$(node).val(telObj.getNumber());
};

});
$(node).val(telObj.getNumber());
};
}

$(document).on('daPageLoad', setupPhoneInputs);
window.addEventListener("alTranslationsLoaded", setupPhoneInputs);
})();
28 changes: 25 additions & 3 deletions docassemble/ALToolbox/test_translation_strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,16 +162,38 @@ class TestAltoolboxJsStrings(unittest.TestCase):
def _static_path(self, name: str) -> str:
return os.path.join(os.path.dirname(__file__), "data", "static", name)

def test_every_string_passed_to_underscore_is_listed(self) -> None:
def test_loader_uses_the_json_catalog_endpoint(self) -> None:
with open(self._static_path("al_translate.js"), encoding="utf-8") as loader:
source = loader.read()
self.assertIn("al_translations.json?lang=", source)
self.assertNotIn("al_translations.js?lang=", source)

def test_every_string_passed_to_the_translator_is_listed(self) -> None:
with open(self._static_path("TextCounter.js"), encoding="utf-8") as counter_js:
source = counter_js.read()
found = set(re.findall(r'\b_\(\s*"((?:[^"\\]|\\.)*)"', source))
self.assertTrue(found, "expected TextCounter.js to call _()")
with open(
self._static_path("phone-number-validation.js"), encoding="utf-8"
) as phone_js:
source += phone_js.read()
found = set(
re.findall(r'\b_\(\s*"((?:[^"\\]|\\.)*)"', source)
+ re.findall(r'\btranslate\(\s*"((?:[^"\\]|\\.)*)"', source)
)
self.assertTrue(found, "expected ALToolbox JavaScript to call a translator")
self.assertTrue(
found.issubset(set(ALTOOLBOX_JS_STRINGS)),
f"missing from ALTOOLBOX_JS_STRINGS: {found - set(ALTOOLBOX_JS_STRINGS)}",
)

with open(
os.path.join(os.path.dirname(__file__), "PhoneNumberDataType.py"),
encoding="utf-8",
) as phone_datatype:
self.assertIn(
'This phone number doesn\'t look right. Note that a non-US number needs a "+" before the number.',
phone_datatype.read(),
)

def test_the_shipped_word_file_covers_every_string(self) -> None:
import yaml # type: ignore[import-untyped]

Expand Down
15 changes: 12 additions & 3 deletions docassemble/ALToolbox/translation_strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,19 @@

__all__ = ["add_translations", "translate", "translation_catalog"]

# Every string ALToolbox's own JavaScript passes to `_()`. Nothing reads this at
# runtime; it is the checklist a translator needs, and a test keeps it honest by
# grepping the shipped .js files.
# Every string ALToolbox's own JavaScript or custom datatype passes to the
# translator. Nothing reads this at runtime; it is the checklist a translator
# needs, and a test keeps it honest by grepping the shipped source files.
ALTOOLBOX_JS_STRINGS = [
"Change country, selected ${countryName} (${dialCode})",
"Select country",
"List of countries",
"Search",
"Clear search",
"No results found",
"1 result found",
"${count} results found",
'This phone number doesn\'t look right. Note that a non-US number needs a "+" before the number.',
"You have entered %d character.",
"You have entered %d characters.",
]
Expand Down
Loading