[Solved] Convert Locale to localised display name

Creating a macro - Writing a Script - Using the API (OpenOffice Basic, Python, BeanShell, JavaScript)
Post Reply
ah8
Posts: 14
Joined: Sat Mar 23, 2024 2:46 pm

[Solved] Convert Locale to localised display name

Post by ah8 »

Hi all,

for a selection list in a GUI dialogue, I need to figure out the following three things:

1. All languages known to OpenOffice (i.e. all installed locales).
2. All languages, for which a spell checker is available.
3. All languages used in the current document.

For these three problems I found the following three solutions:

Code: Select all

' All languages known to OpenOffice (i.e. all installed locales)
aLocales = createUnoService("com.sun.star.i18n.LocaleData").getAllInstalledLocaleNames()

' All languages, for which a spell checker is available
aLocales = createUnoService("com.sun.star.linguistic2.LinguServiceManager").SpellChecker.Locales

' All languages used in the current document
aLocales = ThisComponent.getDocumentLanguages(1,999) '1: only return Western languages, 999: an arbitrarily chosen maxCount parameter
All return values are arrays of type com.sun.star.lang.Locale, which, in turn, is a structure with the following components (https://www.openoffice.org/api/docs/com ... ocale.html):

Code: Select all

Language        specifies an ISO Language Code.  
Country         specifies an ISO Country Code.  
Variant         contains a variant of the locale; codes are vendor and browser-specific.  
To display the results in the GUI, I need to convert them to a display name. For that, I found the following function:

Code: Select all

createUnoService("com.sun.star.i18n.LocaleData").getLanguageCountryInfo(aLocales(i))
This returns a structure com.sun.star.i18n.LanguageCountryInfo, with the following components (http://www.help.openoffice.org/api/docs ... yInfo.html):

Code: Select all

Language                ISO-639 language code, for example, "en" or "de" 
LanguageDefaultName     Descriptive language name, for example, "English" or "German" 
Country                 ISO-3166 country code, for example, "US" or "DE" 
CountryDefaultName      Descriptive country name, for example, "United States" or "Germany" 
Variant                 A variant name 
The Name entries in there are almost what I need, except that they always contain the default English names. This would not be a problem if the last function (ThisComponent.getDocumentLanguages(1,999)) would not – for some strange reason and against the specification – already perform this transformation, and return a display name instead of the ISO language codes.

However, it returns localised names, i.e. instead of 'English (United States)' or 'German (Germany)' I get something like 'Englisch (USA)' and 'Deutsch (Deutschland)'. While this is actually preferable for the GUI, I need to convert the display name back to ISO codes once the user has made their selection, and the only solution I have come up with so far is to iterate through all available locales, generate the display name and compare it to the selection, which will obviously fail if the compared display names are in different languages.

So here are the questions: Is there a way to tailor the function to obey the GUI's locale settings and return localised names, or is there an alternative way to convert locales to localised display names, or is there an alternative way to find all the languages used in the current document?

Thanks, and best regards,
ah8
Last edited by MrProgrammer on Fri Aug 02, 2024 8:36 pm, edited 1 time in total.
Reason: Tagged ✓ [Solved] ah8 used two passes -- MrProgrammer, forum moderator
OpenOffice 4.x on Debian 10+
JeJe
Volunteer
Posts: 2908
Joined: Wed Mar 09, 2016 2:40 pm

Re: How can a Locale be transformed into a localised display name?

Post by JeJe »

You're using ThisComponent.getDocumentLanguages(1,999) to list the languages which are localised eg as "Englisch (USA)" and you want to derive the Country again from that localised name after the selection? Is that what you're asking?

The result for ThisComponent.getDocumentLanguages(1,999) includes the country so can't you just use the itemdata property in the listbox or combobox to store that value with each list item?
(Name) (Value Type) (Value) (AccessMode)
Country string GB
Language string English (UK)
Variant string ""
Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
ah8
Posts: 14
Joined: Sat Mar 23, 2024 2:46 pm

Re: How can a Locale be transformed into a localised display name?

Post by ah8 »

Yes, that is one of the options I'm asking for. But no, the country code alone is not sufficient, since a language is only unambiguously identified by a combination of country and language code. The language code, however, is overwritten by the localised display name.

I found the source code, where this is done (https://docs.libreoffice.org/sw/html/un ... tml#l03871). Reduced to the essential bits, it looks like this:

Code: Select all

uno::Sequence< lang::Locale > SAL_CALL SwXTextDocument::getDocumentLanguages(::sal_Int16 nScriptTypes,::sal_Int16 nMaxCount )
{
	...
	std::set< LanguageType > aAllLangs;
	...
	' languages are collected in  aAllLangs
	...
	uno::Sequence< lang::Locale > aLanguages( nMaxCount );
	...
	sal_Int32 nCount = 0;
	for (const auto& rLang : aAllLangs)
	{
		...
		if (LANGUAGE_NONE != rLang)
		{
			pLanguage[nCount] = LanguageTag::convertToLocale( rLang );
			pLanguage[nCount].Language = SvtLanguageTable::GetLanguageString( rLang );
			nCount += 1;
		}
	}
	return aLanguages;
}
Apparently, languages are internally represented by a type called LanguageType, which is essentially a 16-bit number. I guess, that is the same number as used for the UNO service ".uno:Language". This is the service recorded by the macro recorder when setting the language via the GUI:

Code: Select all

sub Main
rem ----------------------------------------------------------------------
rem define variables
dim document   as object
dim dispatcher as object
rem ----------------------------------------------------------------------
rem get access to the document
document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")

rem ----------------------------------------------------------------------
dim args1(0) as new com.sun.star.beans.PropertyValue
args1(0).Name = "Language"
args1(0).Value = 1031

dispatcher.executeDispatch(document, ".uno:Language", "", 0, args0())

end sub
A way to convert locale and display names to this internal number and vice versa would also be helpful, but I couldn't find a way to do any of that either.
OpenOffice 4.x on Debian 10+
JeJe
Volunteer
Posts: 2908
Joined: Wed Mar 09, 2016 2:40 pm

Re: How can a Locale be transformed into a localised display name?

Post by JeJe »

Have you seen this thread?

viewtopic.php?p=392012#p392012
Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
ah8
Posts: 14
Joined: Sat Mar 23, 2024 2:46 pm

Re: How can a Locale be transformed into a localised display name?

Post by ah8 »

Yes, I've seen that. Unfortunately, the link to the code is no longer valid, and there's only the help text in the post, so that's not much help.

However, by pure chance I found another option that at least partially solves my problem: there is the UNO service ".uno:LanguageStatus", that accepts the localised display name, so I can use it without having to convert it to locales.

Unfortunately, it only accepts the localised version, so I still have to use locales for the default English names. Here I'm currently stuck with the problem that the data stored in ItemData somehow gets lost, but I think I'll eventually find out why. (Maybe because I'm trying to store a structure in ItemData?)

That still leaves the problem of different list boxes displaying the items in different languages, so I'm still looking for a way to get localised display names. But at least technically it should work.
OpenOffice 4.x on Debian 10+
JeJe
Volunteer
Posts: 2908
Joined: Wed Mar 09, 2016 2:40 pm

Re: How can a Locale be transformed into a localised display name?

Post by JeJe »

I think, from memory, if you're adding or removing items when there's itemdata set, that can give problems. You can add all the items first, before setting the itemdata. Or it might be avoided by only adding items after items with itemdata set not before them - can't remember on that point. Or you could store the itemdata in a separate hidden listbox.

Storing a struct in ItemData shouldn't be a problem - I've found I can even store a collection in a dialog listbox itemdata instead of needing a Global variable for it. Create a hidden listbox specifically for the collection, add an item, then set the itemdata to your collection. Collections of course can contain items with structs.
Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
ah8
Posts: 14
Joined: Sat Mar 23, 2024 2:46 pm

Re: How can a Locale be transformed into a localised display name?

Post by ah8 »

You're right. Inserting a new item into the list box deletes the item data of the previously inserted item. Thereby it doesn't matter, where the new item is inserted, at the beginning, at the end, before or after the previously inserted item, the effect is always the same.

Most likely the item data of all existing items in the list will be erased, but I can't say for sure, as in my tests only the immediately preceding item had valid item data left.

Inserting the item text in a first pass and the item data in a second solved the problem.
OpenOffice 4.x on Debian 10+
ah8
Posts: 14
Joined: Sat Mar 23, 2024 2:46 pm

Re: How can a Locale be transformed into a localised display name?

Post by ah8 »

A little update regarding the item data issue: The problem of lost item data only occurs when the list items are added to the list box control (com.sun.star.awt.UnoControlListBox). If they are inserted into the list box model (com.sun.star.awt.UnoControlListBoxModel), accessible through the Model property of the list box control, then the item data is preserved as expected.
OpenOffice 4.x on Debian 10+
Post Reply