Localisation

From Crusader Kings II Wiki
(Redirected from Localization)
Jump to navigation Jump to search

Localisation files contain all the text that gets displayed on the screen, with the exception of character names (for example William or Matilda). These files are in .csv, or Comma-Separated Values format, which can be opened in a text editor or spreadsheet program like Microsoft Excel or OpenOffice Calc. Despite the name, they are actually separated with semicolons.

Values[edit]

The game loads all localisation files in the localisation folder, and will overwrite any vanilla strings with a mod's. All values should be added to new .csv files that do not share a name with any localisation file from vanilla or another mod. It is acceptable to copy existing .csvs into your mod's localisation folder, and then clear it of data and rename it, rather than creating new ones from scratch.

Note that no added value can contain a semi-colon. Values also should not be more than 1023 characters long - anything above that will not be displayed and will be logged to error.log.

Code Name[edit]

The leftmost column of each row of a .csv contains how an object is referred to in the code. If there is no row with the code name, the code name will be displayed instead of any text.

Events[edit]

For each event, the code will look up the string you used for "desc" and the string you used for each option's "name". So if you wrote an event:

character_event = {
	id = 76411467
	desc = "EVTDESC76411467"
	
	is_triggered_only = yes
	
	option = {
		name = "EVTOPTA76411467"
	}
	option = {
		name = "EVTOPTB76411467"
	}
}

You would need to add strings "EVTDESC76411467", "EVTOPTA76411467", and "EVTOPTB76411467"

Decisions[edit]

For each decision's name, the event will look up its title, and for the text that comes up when you mouse-over for long enough it will look that up with "_desc" appended to it. You can also use "_desc_extra" in order to show text after the Requirement section of the tooltip. So if you wrote an event:

do_nothing = {
	potential = {
	}
	allow = {
	}
	effect = {
	}
	revoke_allowed = {
		always = no
	}
	ai_will_do = {
		factor = 0
	}
}

You would need to add strings "do_nothing", "do_nothing_desc", and, optionally, "do_nothing_desc_extra".

Objectives[edit]

For objectives, i. e., plots and ambitions, you will need to define {objective_name}_title and {objective_name}_desc. For example, if your plot is to annoy someone:

plot_annoy = {
         {plot code}
        }

You will need to add strings "plot_annoy_title" and "plot_annoy_desc":

plot_annoy_title;Annoy [This.GetBestName];Agacer [This.GetBestName];[This.GetBestName] nerven;;Molestar [This.GetBestName];;;;;;;;;x
plot_annoy_desc;You nefariously annoy [This.GetName];Vous agacez malfaisant [This.GetName];Ihr nervt [This.GetBestName] schändlich;;Molestas nefariamente [This.GetName];;;;;;;;;x

(If you can't translate your message into the other languages, you can leave those fields blank; the English will be used by default.)

Others[edit]

For cultures, religions or titles, will go with the name of the added title. For example, if you added the title "e_aaa" to landed_titles, with culture "fictoid" in cultures and religion "nonsensism" in religions, you would need to create a row for each of them.

It is possible to localize the name of the title apart for culture (a Greek King is called Despot for example) for character type too so to replace the Doge title for the ruler of Republic with for example "Prince" we could use the key city_duke so as you can change the name of the title itself to "Principality" using city_duchy_of, you could mix this with culture (city_duke_roman and city_duchy_of_roman for example) and for religion (city_duke_catholic and city_duchy_of_catholic). The equivalents temple_duke and temple_duchy_of also exists.

If a title need a particular title that is not tied to culture or religion but to the title itself then you can add the line "title = <localization_key>" in the title definition in /common/landed_titles/landed_titles.txt where the title is defined. For example if the ruler of "e_aaa" instead of the default title of "Emperor" held historically the title of "Supreme King" you should add the line "title = supreme_king_desc" and then add a corresponding line in the localization file.

Loading[edit]

Loading tips appear below loading_screens and are defined with hardcoded keys:

LOADING_TIP_0
LOADING_TIP_1
...
LOADING_TIP_54

Note that all tips including and after the first empty one will be ignored.

The localization of loading steps can also be changed by overriding the associated keys from text1.csv (PROC_FLAGS, LOAD_FLAGS, LOAD_GFX, etc.)

Languages[edit]

The next three columns contain its name in English, French, and German. The column after German is unused, but the column after that is Spanish. If any of the used columns are left blank, the text will not appear to users running the game in that language, so it is preferable to copy over the data from the column you did write. In newer patches, English localisation will appear for a language where the column is blank. Therefore, you can now simply not include any languages beyond English, and simply end the localisation line with ;;;;;;;;;;;;;x instead.

All Examples[edit]

All of the examples, viewed by a text editor, would look like

EVTDESC76411467;A or B?;A ou B?;A oder B?;;A o B?;;;;;;;;;x
EVTOPTA76411467;A;A;A;;A;;;;;;;;;x
EVTOPTB76411467;B;B;B;;B;;;;;;;;;x
do_nothing;Do Nothing;Ne Rien Faire;Nichts Tun;;No Hacer Nada;;;;;;;;;x
do_nothing_desc;You refuse to do anything.;Vous refusez de faire quoi que ce soit.;Sie weigern sich, irgendetwas zu tun;;Usted se niega a hacer cualquier cosa;;;;;;;;;x
e_aaa;Aaa;Aaa;Aaa;;Aaa;;;;;;;;;x
fictoid;Fictoid;Fictoide;Belletristoid;;Ficcioide;;;;;;;;;x
nonsensism;Nonsensism;Non-sensisme;Unsinnismus;;Nonsensismo;;;;;;;;;x
city_duke;Prince;Prince;Fürst;;Príncipe;;;;;;;;;x
city_duchy_of;Principality of;Principauté de;Fürstum von;;Principado de;;;;;;;;;x
city_duke_roman;Proconsul;Proconsul;Proconsul;;Procónsul;;;;;;;;;x
city_duchy_of_roman;Commune of;Commune de;Kommune von;;Comune de;;;;;;;;;x
supreme_king_desc;Supreme King;Roi suprème;Oberster König;;Rey supremo;;;;;;;;;x

Commands[edit]

More dynamic localisation can be achieved by using localization commands, to change words based on a condition.

As of patch 2.8, they work in all tooltips, in particular:

  • Event description and options
  • Decisions name and description
  • Character modifier descriptions, since patch 2.3
  • Nicknames, since patch 2.3
  • Character opinion tooltips, where ROOT is the judging person and FROM is the person being judged

The name of scopes and commands are hardcoded and thus can't be changed. Some commands have:

  • a 'Cap' suffix version, that will capitalize the first letter, for use as first word of a phrase.
  • an 'Opp' suffix version, that will do the opposite: GetManWomanOpp prints 'man' if character is a woman.

Warning: commands are case sensitive (getName (invalid) vs GetName (valid)).

Gender[edit]

There are localization commands to display predefined words that vary based on character gender:

Command Scope Description
GetHerHim (GetHerHimCap, GetHerHimOpp) character Prints 'him' or 'her' based on the character's gender.
GetObjectPronoun character
GetHerHis (GetHerHisCap, GetHerHisOpp) character Prints 'his' or 'her' based on the character's gender.
GetPossPronoun character
GetHersHis character
GetHerselfHimself character Prints 'himself' or 'herself' based on the character's gender.
GetReflexivePronoun character
GetSheHe (GetSheHeCap, GetSheHeOpp, GetSheHeCapOpp) character Prints 'he' or 'she' based on the character's gender.
GetSubjectPronoun (GetSubjectPronounCap) character
GetManWoman (GetManWomanOpp) character Prints 'man' or 'woman' based on the character's gender.
GetBoyGirl (GetBoyGirlCap, GetBoyGirlOpp, GetBoyGirlOppCap) character Prints 'boy' or 'girl' based on the character's gender.
GetGirlWomanBoyMan character Prints 'boy', 'man', 'girl' or 'woman' based on the character's gender and age.
GetMaleFemale character Prints 'male' or 'female' based on the character's gender.
GetHusbandWife (GetHusbandWifeOpp) character Prints 'husband' or 'wife' based on the character's gender.
GetFatherMother (GetFatherMotherCap) character Prints 'father' or 'mother' based on the character's gender.
GetSonDaughter (GetSonDaughterCap) character Prints 'son' or 'daughter' based on the character's gender.
GetMasterMistress character
GetLadLass character
GetLordLady character
GetKingQueen character
GetPatriarchMatriarch character
GetBrotherSister character

Character and title names[edit]

Character and title naming commands, with examples based on King Louis VI 'the Fat' Capet of France.

Command Scope Example Notes
GetFirstName character Louis
GetFirstNameWithNick character Louis 'the Fat'
GetTitle character King
GetTitledName character King Louis VI of France
GetTitledNameWithNick character King Louis VI 'the Fat' of France
GetTitledFirstName character King Louis VI Titular name of character
GetTitledFirstNameWithNick character King Louis VI 'the Fat'
GetTitledFirstNameNoRegnal character Like GetTitledFirstName, but uses birth names for Popes and other characters with regnal names.
GetDynName character Louis Capet
GetOnlyDynastyName character Capet
GetLastWordInDynastyName character Capet Will split the character's dynasty names on spaces and apostrophes, and return the last word:
  • d'Anjou becomes Anjou
  • de Hauteville becomes Hauteville
GetBestName character King Louis the Fat The logic is to:
  • Use nickname if any (King Louis the Fat)
  • Default to primary title (King Louis of France)
GetBestNameWithoutRegnalNumber character
GetFullName character

title

Louis Capet

Kingdom of France

GetPrimaryTitles character King of France

etc.

GetBaseName title France
GetName title France Warning: does not work on characters !
GetFullBaseName title Kingdom of France
GetRulerTitle title King
GetAdjective title French
GetFOA title Your Majesty Form of address
GetTitledGrandMasterName society
GetTitledNextGrandMasterName society

Wonders[edit]

Localisation commands referring to wonders or wonder upgrades.

Command Scope Notes
GetName Wonder/Upgrade
GetTypeName Wonder/Upgrade
GetWonderAge Wonder Would print a number of how many years a wonder has been around, since its first stage/tier was completed.
GetUpgradeAge Upgrade Would print a number.
GetFoundingDate Wonder Date when first brick was layed down.
GetFirstStageCompleteDate Wonder
GetCurrentStageCompletedDate Wonder
GetDesc Wonder/Upgrade Would print whatever the desc is currently set to. Could be used to update the text, only by appending something new to it.
GetPercentComplete Upgrade
GetBuildProgressMonths Upgrade
GetEstimatedFinishDate Upgrade
GetFlatCost Upgrade
GetFlatCostWithoutModifier Upgrade
GetTickingCost Upgrade
GetTickingCostActive Upgrade
GetTickingCostWithoutModifier Upgrade
GetConstructionStatus Upgrade
GetAllowTriggerDescription Upgrade
GetActiveTriggerDescription Upgrade
GetCompletionDate Upgrade

Other built-in commands[edit]

Command Scope Description
GetAgeYears character Displays the age of the character
GetName religion
culture
variable
province
government
modifier
offmap
wonder
upgrade
Displays the name of the scope: Culture.GetName, Religion.GetName, [Root.test_var.GetName], [Root.modifier_name.GetName], Offmap.GetName
GetFullName religion Displays the defined full name of the religion (religion_full).
GetValue variable [Root.PrimaryTitle.test_var.GetValue]
GetID character/province Displays the internal ID of the scope (character ID, province ID, ...). This is useful for logging or debug purposes.
GetGroupName religion Display the parent group name: the [Root.Religion.GetGroupName] world
GetFromRelation

GetFromFromRelation
GetFromFromFromFromRelation

character Prints the relation you have with FROM (or deeper in event chain), for example 'mother' or 'son'. Warning: adding any scope to the beginning breaks it, it must be used by itself [GetFromRelation].
GetFromVsFromFromRelation
character Variant of above comparing the sender to the previous sender in an event chain.
GetScriptureName religion Prints the holy book of the linked character's religion: The words of the [Root.Religion.GetScriptureName] are certain!
GetHighGodName (GetHighGodNameCap) religion Reference to the religion's high_god_name localization: ...worthy to be [Root.Religion.GetHighGodName]'s servant.
GetRandomGodName (GetRandomGodNameCap) religion Reference to the religion's god_names localization list: Oh [Root.Religion.GetRandomGodName], what am I doing?
GetRandomEvilGodName (GetRandomEvilGodNameCap) religion Reference to the religion's evil_god_names localization list: This is the work of [Root.Religion.GetRandomEvilGodName]!
GetPriestTitle religion a group of [Root.Religion.GetPriestTitle]s have arrived at your court
GetPietyName religion Reference to the religion's piety_name localization: ...to improve [This.GetHerHis] [This.Religion.GetPietyName]...
GetCrusadeName religion Reference to the religion's crusade_name localization: ...declared a [Root.Religion.GetCrusadeName].
GetJobTitle character Councillor job name: ...carry out [From.GetHerHis] duties as [From.GetJobTitle].
GetChancellorName

GetMarshalName
GetTreasurerName
GetSpymasterName
GetLordSpiritualName
GetMyChancellorName
GetMyMarshalName
GetMyTreasurerName
GetMySpymasterName

character Similar to GetJobTitle ?
GetProposedLaw title ...to institute the [From.GetProposedLaw] Law
GetLawProposer character I have been convinced by [From.GetLawProposer] to institute the [From.GetProposedLaw] Law.
GetPlot character
GetDay any
GetWeekday any
GetDesc government/religion Description of government or religion.

[Government.GetDesc]

GetFeatures government/religion/culture Features of government, religion or culture

[Religion.GetFeatures]

GetDeathReason (GetDeathReasonCap) character

[GetDeathReasonCap] on [GetDeathDate]

GetDeathDate character

[GetDeathReasonCap] on [GetDeathDate]

GetBirthDate character

born [GetBirthDate]

GetFromRootInsult

GetFromFromRootInsult

character Returns an insulting adjective and noun based on the target character's traits and physical sex, e.g., "filthy lecher", as regarded by the first scope to second scope (e.g., GetFromRootInsult is from FROM to ROOT) -- avoiding self-deprecating insults for traits shared in common (e.g., if both Lustful.png Lustful, the insulter is unlikely to call them a lecher). As with GetFromRelation, it must be used by itself without any scope command in front.

[GetFromRootInsult]

GetRootFromInsult

GetRootFromFromInsult

character As above but in opposite direction—ROOT to FROM, etc.

[GetRootFromInsult]

GetRootFromInsultNoun character As above but just the noun, e.g. "lecher".

[GetRootFromInsultNoun]

GetFromRootInsultNounAdj

GetFromFromRootInsultNounAdj

character Returns an insult in the opposite order of "noun adjective", sent by the first scope to the second scope (GetFromFromRootInsultNounAdj = FROMFROM to ROOT). Generally used by localised non-English languages which have a reverse-ordered adjective structure (e.g., English "filthy dog" (adjective noun) is French "chien sale" (noun adjective)). Must be used without a scope.

[GetFromRootInsultNounAdj]

GetRootFromCompliment

GetRootFromFromCompliment

character Returns a complimentary phrase in the form of "adjective noun", e.g., "brave warrior", from the character in ROOT scope to the character in the FROM scope, based on the traits of FROM. As with similar localisation commands with scopes listed in the body of the name, no scope prefix can be used.
GetRootFromComplimentNounAdj character Returns reverse-ordered "noun adjective" compliment, instead of the normal "adjective noun" compliment, for languages (e.g., French) with non-English adjective order.
GetExpiryDate modifier Returns the expiration date of the character's, province's, or holding's named modifier. e.g., [Root.modifier_name.GetExpiryDate]
GetCurrency offmap The name of the offmap power's currency (e.g., "Grace").
GetPolicy offmap The offmap power's current political alignment.
GetPrevPolicy offmap The offmap power's last political alignment before the current one. Blank if the offmap power hasn't yet had a different policy.
GetPrevStatus offmap The offmap power's last political state before the current one. Blank if the offmap power hasn't yet had a different status.
GetStatus offmap The offmap power's current political state.
GetScopes any Shows a list of all event targets set, and what each scope corresponds to. Note that it only works in scopes; once you've promoted to a specific entity (E.G., a character), scope properties are unavailable.

Other commands are often hardcoded variables, only available in a specific context, and so useless for modding:

  • GetAmbition
  • GetBornAndDeathDate
  • GetDelayedLiegeOpinion
  • GetDelayedPlayerOpinion
  • GetDemesneSizeRatio
  • GetDiploGiftSize
  • GetDiplomacy
  • GetDiplomacyBreakdown
  • GetHighestTitles
  • GetInstantLiegeOpinion
  • GetInstantPlayerOpinion
  • GetIntrigue
  • GetIntrigueBreakdown
  • GetIsValidDesc
  • GetLearning
  • GetLearningBreakdown
  • GetMartial
  • GetMartialBreakdown
  • GetMonthlyIncome
  • GetMonthlyPiety
  • GetMonthlyPietyBreakdown
  • GetMonthlyPrestige
  • GetMonthlyPrestigeBreakdown
  • GetObjective
  • GetPietyCost
  • GetPlayerRelation
  • GetPlayerRelationCap
  • GetStatusInfo
  • GetStewardship
  • GetStewardshipBreakdown
  • GetTitleIncParents

There are also Localisation keys. These are less flexible than commands, and will only work where the game is hardcoded to provide them. They appear to be a legacy feature.

Custom commands[edit]

As of patch 2.6 it is possible to add custom localization commands using a scripted logic based on conditions.

These commands are defined in localisation\customizable_localisation folder and don't impact the checksum.

The structure is:

defined_text = {
	name = MyCustomCommand

	use_first_valid = yes # Defaults to no

	text = {
		trigger = {
			# Conditions to use KEY_1
		}
		localisation_key = KEY_1
	}
	text = {
		trigger = {
			# Conditions to use KEY_2
		}
		localisation_key = KEY_2
	}	
}

When using [MyCustomCommand] in a localization key, it will be replaced either by KEY_1 or KEY_2 value, depending on the evaluation of the conditions.

If several of the keys have their conditions met, unless use_first_valid = yes is used, one of them will be picked at random. If use_first_valid = yes is used, then the first key that has its condition met will be used.

Note that it is not possible to override hardcoded localization commands (for instance [GetBestName]) this way.

As of patch 2.7 custom localisation can reference localization strings that themselves contain custom localisation.

Scopes[edit]

To use a localization command with a scope chain, use the following pattern:

[<Scope1>.<Scope2>...<Command>]
  • Commands should always be placed within [], otherwise they won't work.
  • The first part is the character who is being linked to (Root, Spouse, From, ...)
  • The last part is a command to display text (GetHerHim, GetFullName, ...)

For example, here are the strings for the "request council job" events:

It is sad that [Root.Liege.GetTitledFirstName] is employing [Root.job_marshal.GetTitledFirstName] as [Root.Liege.GetHerHis] marshal. I am more competent and would be a better marshal!

[From.GetBestName] claims that [From.GetSheHe] would be a better marshal than [Root.job_marshal.GetTitledFirstName], and petitions that [From.GetSheHe] should be given the title of Marshal of the [Root.PrimaryTitle.GetFullName].

Scope commands, similar to scripting scopes:

  • Actor
  • ActorExtra
  • AdultExtra
  • Betrothed
  • Capital
  • ChildExtra
  • Clan
  • County
  • Culture
  • Duchy
  • Employer
  • Father
  • FatherOfUnborn
  • From
  • FromFrom
  • FromGetSheHe
  • GetLiege
  • Government
  • Governor (offmap)
  • GovernorTitle (offmap)
  • GrandMaster (society)
  • Guardian
  • Heir
  • Holder (province or title)
  • Host
  • job_chancellor
  • job_marshal
  • job_spiritual
  • job_spymaster
  • job_treasurer
  • Killer
  • Kingdom
  • Liege
  • Location
  • Lover
  • Mother
  • New
  • NextGrandMaster (society)
  • Offmap
  • OldestChild
  • OriginalOwner (artifact / wonder)
  • Owner (artifact / wonder)
  • ParentReligion
  • Player
  • PlotTarget
  • PlotTargetTitle
  • PrevRuler (offmap)
  • Province (from wonder)
  • PrimaryTitle
  • RealFather
  • Realm
  • Recipient
  • RecipientExtra
  • Regent
  • Reincarnation
  • RelHead
  • Religion
  • Root
  • Ruler (offmap)
  • SeaZone
  • SecretReligion
  • Siege
  • Society
  • Spouse
  • SupportedClaimant
  • SupportedClaimantTitle
  • ThePope
  • ThirdPartyCharacter
  • ThirdPartyTitle
  • This
  • Title
  • TopLiege
  • TrueFather
  • TrueReligion
  • Twin
  • Wonder (from province)

You can scope directly to specific offmap powers by using their name, e.g.:

[offmap_china.GetName]

Since Patch 3.0 you can also scope to landed titles, religions, religion groups, cultures and culture groups in loc using their name, e.g.:

[k_norway.GetName]
[k_papacy.Holder.GetTitledName]
[catholic.GetName]
[christian.GetName]
[norwegian.GetName]
[north_germanic.GetName]

Note that referencing a group is just a different way to reference the first member of the group, it will not scope to the group itself.

Additionally, the following dynamic localization scopes are available:

  • The names of saved event targets[1] (save_event_target_as, save_global_event_target_as, save_persistent_event_target)
  • The names of numeric variables (set_variable), used with GetName or GetValue
  • The names of timed modifiers, used with GetName or GetExpiryDate

Special Characters[edit]

Some sets of characters perform special functions.

NOTE: Save the file with the Windows-1252 encoding so the color codes work correctly.

Command Description
\n Line break. Works only in certain cases.
§Bxxx§! Prints the text xxx in blue.
§Cxxx§! Prints the text xxx in grey.
§Fxxx§! Prints the text xxx in brown.
§Gxxx§! Prints the text xxx in green.
§Kxxx§! Prints the text xxx in dark red.
§Mxxx§! Prints the text xxx in light yellow.
§Pxxx§! Prints the text xxx in pink.
§Rxxx§! Prints the text xxx in red.
§Yxxx§! Prints the text xxx in yellow.
§Zxxx§! Prints the text xxx in dark green.
¤ Prints the symbol for personal wealth.

Languages[edit]

French[edit]

A set of localization commands dedicated for French translations is included in \localisation\customizable_localisation\00_customizable_localisation_FR.txt. For more info: Traduction remaniée - Crusader Kings II 2.7.x (in French).

French custom localisation strings are located in \localisation\FR.csv.

German[edit]

A set of localization commands dedicated for German translations is included in \localisation\customizable_localisation\00_customizable_localisation_DE.txt.

German custom localisation strings are located in \localisation\DE.csv.

Spanish[edit]

A set of localization commands dedicated for Spanish translations is included in \localisation\customizable_localisation\00_customizable_localisation_ES.txt.

Spanish custom localisation strings are located in \localisation\SPA.csv.

Editing[edit]

Using a text editor[edit]

Each line of a Paradox localisation file should look like this:

CODE;ENGLISH;FRENCH;GERMAN;;SPANISH;;;;;;;;;x

The number and position of the semicolons is important, as it defines which data goes in which language and when the line is over.

Lines beginning with "#" are considered comments, so they do not need semicolons. Blank lines are also ignored.

Localisation files must be saved using a single-byte character encoding (ISO-8859-1?) rather than UTF-8. They must end with a single empty line.

Using spreadsheet software[edit]

If opened as a spreadsheet, each area between the semicolons would get its own column and each line of the localisation file would get its own row. If you are asked to choose a "delimiter" character, specify that the values are separated by semicolons and that there is no text delimiter.

Excel[edit]

Important note: If your system uses English number separators (i.e. comma for thousands, period for decimal places) then Excel won't be able to load or save localisation data. To fix this, go to Excel > Excel Options > Advanced and un-check the "Use System Separators" option. Then change the Decimal Separator to comma. This causes Excel to use semicolons instead. You can toggle the System Separators box whenever you need to do other work in Excel.

OpenOffice Calc/LibreOffice Calc[edit]

Importing localization csv files with OpenOffice Calc

Some tips to work with localization in OpenOffice Calc or LibreOffice Calc:

  • Import settings: Separated by semicolon, no Text delimiter, ISO-8859-1 or Western 1252/Latin 1 encoding.
  • Use Right-click/Column Width... to set proper width in order to have the languages to translate to/from visible at the same time, in order to avoid horizontal scrolling.
  • Use Right-click/Format Cells... -> Alignment tab -> Wrap text automatically for the language(s) being worked on, to always see the whole text.
  • Ensure all the x are aligned in same column (column O if using vanilla number of columns), otherwise the blank line at the end of the file may be removed.
  • Check spelling per column (one language at a time).
  • Make sure text does not contain semicolon, otherwise it will be truncated in game, and when re-importing it will appear split into multiple columns.
  • When saving, use current format.

Command line[edit]

It is possible to use the very poorly documented command line features of OpenOffice or LibreOffice to create a batch file that will automatically convert an .ods spreadsheet file into a semicolon-delimited .csv file. You may then drag and drop any .ods file onto this batch file, and it will be automatically converted into a .csv file in the parent directory.

If using LibreOffice, copy and paste the following command into a blank text file, and rename that file to "update_file.cmd" (or any other name of your choice, of course, so long as it retains the .cmd extension):

::Just drag and drop the .ods file onto this batch file to export it.  Much more convenient than going through the Export menu in LibreOffice!
"C:\Program Files\LibreOffice\program\soffice.exe" --convert-to csv:"Text - txt - csv (StarCalc)":59,34,1,1,2/2/2/2/2/2/2/2/2/2/2/2/2/2/2 --outdir .. %1

The same command line will work with OpenOffice with the file path changed accordingly, as both products are from a shared code base. The same command line will work identically on Linux and Mac installations of LibreOffice as well, with the exception of the file path and "%1" parameter which must be changed to suit the operating system.

The gobbledegook in the command line parameter is documented here, but here is a breakdown:

"C:\Program Files\LibreOffice\program\soffice.exe" Absolute file path to the OpenOffice or LibreOffice binary. Using an absolute path allows you to run the command from any folder.
--convert-to csv: Denotes that we want to start a headless client that will run a conversion to the .csv format.
"Text - txt - csv (StarCalc)": Using the CSV filter.
59,34,1,1,2/2/2/2/2/2/2/2/2/2/2/2/2/2/2 In order from left to right:
  • Field Separator: 59 = semicolon
  • Text Delimiter: 34 = quotation-mark
  • Character Set: 1 = Windows-1252
  • First Line: 1
  • Cell Formats: "2" = string for all fifteen columns
--outdir .. Export the file to the directory one level closer to the system root.
%1 Passes the absolute filename dropped onto the batch file to the command line.

This allows you to work directly in the .ods format (or any other valid spreadsheet format) in a subfolder of the "/modname/localisation" folder such as "/modname/localisation/src", which means you may take advantage of the spreadsheet software's ability to hide irrelevant columns, enable word wrapping, use cell formatting, assign column widths, set optimal row heights, etc., all without having to run through the "Save a Copy" system dialog in the File menu to save as .csv.

It is also possible to change the --outdir .. (two periods) to --outdir . (one period) to export to the same directory.

A multiple-file variant using Windows NT batch scripting is here, but heed the warning:

::Note that this is very unreliable, for some reason, probably "because Windows".  LibreOffice will enqueue about a dozen or so conversion operations in seemingly random order, and then end.
::To convert all the files, you will have to run this batch file multiple times, or drag and drop each one to update_file.cmd instead.
for %f in (*.ods) do "C:\Program Files\LibreOffice\program\soffice.exe" --convert-to csv:"Text - txt - csv (StarCalc)":59,34,1,1,2/2/2/2/2/2/2/2/2/2/2/2/2/2/2  --outdir .. "%f"

References[edit]