[javascript] Function for making scripts Multilingual  SOLVED

Forum for the PDF-XChange Editor - Free and Licensed Versions

Moderators: Daniel - PDF-XChange, PDF-XChange Support, Vasyl - PDF-XChange, Chris - PDF-XChange, Sean - PDF-XChange, Paul - PDF-XChange, Ivan - Tracker Software, Stefan - PDF-XChange

Mathew
User
Posts: 567
Joined: Thu Jun 19, 2014 7:30 pm

[javascript] Function for making scripts Multilingual  SOLVED

Post by Mathew »

PDF XChange application itself has the ability to change menus and displayed text based on a user's language, but there's no built-in mechanism to extend that to scripts:

The attached script adds a function that allows you to have a separate translation file that can be used to provide alternate translations for a javascript tool. The idea is based on a function in wordpress that has similar functionality.

I named the file somewhat cryptic '1ang.js' to try to get it to load before all other scripts. This may or may not work - seems OK on my system but let me know.

To use, extract the zip file and put the contents in the javascripts folder and restart PDF-XChange. It includes a sample translation file.
1ang v1.1.zip


It adds a single global function __(textToLocalize, domain, params...) -- the function name is a double underscore -- which you use on a plain string in your code.

Code: Select all

// Instead of writing
app.alert("Hello World!");
// make the alert translateable with the 'sample' translation domain
app.alert( __("Hello World!", "sample") );
The function name is a double underscore character.
  • textToLocalize is the text you want to output to the user and be translateable. It must exactly match text in the translation file (including case, punctuation, etc).
    domain refers to the name of the translation file that will be used
    params... are optional strings you want to substitute back into the text after it's been translated. They are referred to in the textToLocalize as %n where n is parameter number: %1 for the first parameter, %2 for the second, etc. This is useful for adding dynamically generated content that would otherwise prevent the translation string from matching. Use %%1 if you want to literally output %1.
The heart of the script functionality is the translation file. The file must be named translationData.domain.json and be saved in one of the Javascripts folders. See the post viewtopic.php?p=186101#p186101 for more information about a tool I made to help with this file.

The included translation file has translations for the following two phrases to German and Italian, using domain 'sample':
  • Hello World!
  • There are %1 options.
If you enter and run in the javascript console:

Code: Select all

__("Hello World!", 'sample')
The output depends on the language you have set for PDF-XChange. For example, if you have it set to Italian, the output will be:

Code: Select all

Salve, mondo!
For the following example

Code: Select all

__("There are %1 options.", 'sample', 12)
If you have language set to German, the output will be:

Code: Select all

Es gibt 12 Optionen.
If the currently set language doesn't match any of the languages in the translation file, it just returns textToLocalize with any provided parameters substituted in. For language Swedish it would return:

Code: Select all

There are 12 options.
Plurals
There is rudimentary support for adding plurals to translations. Whether it is plural is based on the %1 parameter. The format is to put the list of plural options inside square brackets:

Code: Select all

"ENU": {
# Example of using plurals - last one is default
    "There are %1 options.": ["There is only one option.", "There are two options.", "There are three options.", "There are %1 options."]
    }
For language English, the above would give the following output:

Code: Select all

__("There are %1 options.",'sample',1);
//  There is only one option.
__("There are %1 options.",'sample',3);
//  There are three options.
Text that's not recognized as a number, negative numbers and zero, or numbers greater than the list length default to the last item:

Code: Select all

__("There are %1 options.",'sample',12);
//  There are 12 options.
__("There are %1 options.",'sample',"ten");
//  There are ten options.
Limitations
  • I was having some trouble with non-ASCII unicode characters. I think the problem may have been related to text file encoding (must be encoded UTF-8 I think), but if someone who works in an alphabet with extended unicode (such as accents, and other letters like Eszett in German, or Chinese/Japanese/Korean/... characters) has time to try it, I'd like to figure it out.
  • The function must load before you can use it. This is generally going to always be fine for menus, but if you have app.addToolButton() at the beginning of a tool that loads before this function, you may have problems trying to localize the displayed text in the tool button. I don't know how PXE determines the order that files are loaded in the Javascripts folder - I assume it's alphabetically and it's working for me that way - but this may be random luck.
Translation file
Filename must be "translationData.<domain>.json" and saved in the javascripts folder. <domain> should be a unique text string to your script. Set the encoding to 'UTF-8' (I think -- someone more knowledgeable should confirm this).

This file must be formatted as a JSON file except that lines starting with # are stripped out before processing: Use that to add comments as needed.

"Language" is three letter code as output from app.language. The following are listed in the API but there may be more. You can find your language by running app.language in the javascript console:
image.png

"Original Text" is case sensitive and must match exactly including punctuation!

Translation File Format:

Code: Select all

{
"Language": {
    "Original Text": "Translated Text",
# optional comments must be on their own line
    "Original Text 2": "Translated Text 2"
    },
"Language 2": {
    "Original Text": "Translated Text in Language 2"
# Not all items need to be translated in every language
    },
"Language 3": {
# Plurals from v1.0 onwards
    "Original Text": ["Translated Singular", "Translated Plural"]
}
Editing Translation files & Extracting Strings from JavaScript files
I made a tool to both help with editing the translation files, and extracting textToLocalize strings from the javascript file directly.
  • The first page has a field you can paste the textToLocalize strings into so you can edit them with the tool.
  • The second page has form fields that allow you to edit the translations in a more user friendly manner. I've added some buttons to upload the strings to google translate, but it still requires some copy and pasting.
  • The last page is a tool that allows you to extract the textToLocalize strings from a Javascript file.
There's more about this tool on the post below viewtopic.php?p=186101#p186101
TranslationTools v0.6.pdf


Notes
To avoid having to repeat the domain every time this function is called, one could define a function within the script that substitutes in the domain; something like:

Code: Select all

function yourMenuFunction() {
    // function to be used inside a script for domain 'sample'
    const _ = (text, ...args) => __(text, 'sample', ...args);
    // used thus:
    _("Text to be translated.");
...
}
You do not have the required permissions to view the files attached to this post.
Last edited by Mathew on Mon Mar 24, 2025 9:33 pm, edited 30 times in total.
Mathew
User
Posts: 567
Joined: Thu Jun 19, 2014 7:30 pm

Re: [javascript] Function for making scripts Multilingual

Post by Mathew »

I just posted an updated v0.4 but I don't think anyone downloaded previous versions.
It was quite a big change to the parameter replacement - simplified to %1, %2 etc (from $1%s, $2%s). Also moved the translation cache to a local variable.
User avatar
Daniel - PDF-XChange
Site Admin
Posts: 10998
Joined: Wed Jan 03, 2018 6:52 pm

Re: [javascript] Function for making scripts Multilingual

Post by Daniel - PDF-XChange »

Hello, Mathew

Nice, thank you very much Mathew! This looks interesting, to say the least. And to answer your original question, I do not believe that language selection is normally able to be extended to Js toolbar/script items.

Kind regards,
Dan McIntyre - Support Technician
PDF-XChange Co. LTD

+++++++++++++++++++++++++++++++++++
Our Web site domain and email address has changed as of 26/10/2023.
https://www.pdf-xchange.com
Support@pdf-xchange.com
Mathew
User
Posts: 567
Joined: Thu Jun 19, 2014 7:30 pm

Re: [javascript] Function for making scripts Multilingual

Post by Mathew »

v1.1: Fail silently if there's no translation file for a domain. Documented code better. Also updated above.
1ang v1.1.zip
v1.0: I revised it slightly to add option for plurals within a single translation line. Translation files with this option need to use the v1.0 or later version. Also updated above.
1ang v1.0.zip
You do not have the required permissions to view the files attached to this post.
Last edited by Mathew on Wed Jul 31, 2024 5:28 pm, edited 2 times in total.
User avatar
Daniel - PDF-XChange
Site Admin
Posts: 10998
Joined: Wed Jan 03, 2018 6:52 pm

[javascript] Function for making scripts Multilingual

Post by Daniel - PDF-XChange »

:)
Dan McIntyre - Support Technician
PDF-XChange Co. LTD

+++++++++++++++++++++++++++++++++++
Our Web site domain and email address has changed as of 26/10/2023.
https://www.pdf-xchange.com
Support@pdf-xchange.com
Mathew
User
Posts: 567
Joined: Thu Jun 19, 2014 7:30 pm

Re: [javascript] Function for making scripts Multilingual

Post by Mathew »

I made a tool that helps to edit the translation files. It's a pdf file, with forms that are controlled by javascript.

[*Edit: v0.6 added load and save buttons, improved dialog for translate all, renamed button to "commit", improved import from js file to capture the domain and check if more than one domain used in js file, added a tool to compare a template file on page 4 to the language file on page 1 and update the template strings if needed]
TranslationTools v0.6.pdf
If you are extracting the text to localize from a javascript file, use the tool on the last page to get the strings to paste into the translation data file.

If you already have the text to localize from the translationData.<domain>.json and want to edit it, copy the contents of the file, and paste into the form field on the first page. Alternatively you can use the Load button to load the translation file directly, but the load and save buttons need privileged functions, so you'll need to run the following in the javascript window to get them to work:

Code: Select all

var tempReadFile = app.trustedFunction((filePath)=>{app.beginPriv(); return util.stringFromStream(util.readFileIntoStream(filePath));});
var tempSaveFile = app.trustedFunction((doc,cName)=>{app.beginPriv(); return doc.exportDataObject({cName, nLaunch: 0}); });
image(6).png
Load opens a file select dialog to pick a file that gets loaded into the tool.
Save opens a save dialog. If you previously used the Load button, then it will pre-enter the same file name.
Update Template is a helper dialog to update a translation file if the template strings have changed.
Read Translation File loads what's currently in the form field into the tool.

Translating
The main part of the tool is on the second page. Once the translation file is loaded onto the first page and Read Translation File is pressed, the tool on the second page should be loaded with the translations:
image.png
Languages
  • On the left side are the languages currently in the translation file. [Template] is the listing of translation strings that come from the javascript and are copied to every language. To add a language, use the dropdown to select a language, and press the (+) button. For example, adding German:
    image(1).png
Translatable Strings
  • It lists all the translation strings at the center, and if you select one of them, it loads the string and any translation into the fields on the right. The listing shows
    <X> next to strings that have no translation in this language,
    <?> next to a string that doesn't exist in the template.
image(2).png
Language Notes
  • Any notes you want to add, associated with the language translation.
String
  • This is the text from the javascript file that needs a translation
Translation
  • Enter the translated text here
Notes
  • This is notes about the translated text for this particular string.
Delete Translation
  • This button deletes the translation for the currently selected string.
Commit Changes
  • This takes all the changes made to the translations, and updates the file on the first page. It is important you press this before saving or closing the file, otherwise your changes will be lost.
Translate selected string
  • It creates a url and loads the google translate page with this string pre-entered for the currently selected language. There will be a security warning before PXCE opens the page:
    image(3).png
    Copy the translation from the web page and paste back into Translation to use it.
    image(4).png
Translate All
  • This is a fast way to get machine translations for all the strings in one go, but it doesn't always work because google translate sometimes messes with the JSON - particularly if a language uses a different character for quotation marks (it changed some of the quote marks and commas for Japanese, so I had to manually edit those afterwards). The tool creates a JSON string of all the translatable strings, and loads the google translate page with that. Usually it works quite well, and you can copy and paste the translation back into the dialog box.
    image(5).png
    The tool will try to parse this and update all the strings with the translations. If there's a problem with the JSON (usually related to quote marks and commas), it will reopen the dialog.
When you are done editing, remember to press Commit Changes then go back to the first page. You can either select and copy everything in the form field and paste back into the translationData.<domain>.json or use the Save button.

The third page has the listing of languages (if you want to add a language), and also the information the script uses to call google translate. If you use another translation web site, you may be able to edit it to make that work - let me know if I need to change something. I've not figured out how to use any of the API's yet.
You do not have the required permissions to view the files attached to this post.
Last edited by Mathew on Mon Mar 24, 2025 10:18 pm, edited 9 times in total.
Mathew
User
Posts: 567
Joined: Thu Jun 19, 2014 7:30 pm

Re: [javascript] Function for making scripts Multilingual

Post by Mathew »

I updated the translation tool above.
v0.3.4 fixed a bug that duplicated text with newlines in the translation string
v0.3.3 updated slightly (changes color of save button, enables/disables notes field depending if the string exists in that language, flattened the comment text boxes, slightly enlarged input boxes for translation, added icons
User avatar
Dimitar - PDF-XChange
Site Admin
Posts: 2205
Joined: Mon Jan 15, 2018 9:01 am

Re: [javascript] Function for making scripts Multilingual

Post by Dimitar - PDF-XChange »

Thank you.
Mathew
User
Posts: 567
Joined: Thu Jun 19, 2014 7:30 pm

Re: [javascript] Function for making scripts Multilingual

Post by Mathew »

Updated the translation tool to v0.6 above.
  • Added Load and Save buttons, and
  • Added a tool to help update translation files if the strings in the js file get updated. The buttons down the middle:
    • [<<] moves a new string into the translation file template
      [X] deletes a string from the translation file template
      [Fix] changes the string selected on the left to match that on the right side. This is useful if, for example, there's a typo in the original string and there are already translations in the file. This will update the string in the template as well as for any language that has that string.
    image.png
  • The extract tool on the last page now checks for the domain and alerts if more than one domain in a js file.
You do not have the required permissions to view the files attached to this post.
User avatar
Daniel - PDF-XChange
Site Admin
Posts: 10998
Joined: Wed Jan 03, 2018 6:52 pm

[javascript] Function for making scripts Multilingual

Post by Daniel - PDF-XChange »

:)
Dan McIntyre - Support Technician
PDF-XChange Co. LTD

+++++++++++++++++++++++++++++++++++
Our Web site domain and email address has changed as of 26/10/2023.
https://www.pdf-xchange.com
Support@pdf-xchange.com