diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | advtrains/init.lua | 7 | ||||
-rw-r--r-- | advtrains/locale/README.md | 23 | ||||
-rw-r--r-- | advtrains/locale/advtrains.de.tr | 146 | ||||
-rw-r--r-- | advtrains/locale/advtrains.fr.tr | 146 | ||||
-rw-r--r-- | advtrains/locale/advtrains.zh_CN.tr | 146 | ||||
-rw-r--r-- | advtrains/locale/advtrains.zh_TW.tr | 146 | ||||
-rwxr-xr-x | advtrains/locale/gui | 638 | ||||
-rw-r--r-- | advtrains/locale/template.txt | 146 | ||||
-rwxr-xr-x | advtrains/locale/topo.sh | 4 | ||||
-rw-r--r-- | advtrains/po/README.md | 70 | ||||
-rw-r--r-- | advtrains/poconvert.lua | 159 |
12 files changed, 247 insertions, 1387 deletions
@@ -1,4 +1,5 @@ ## Eclipse project files & directories .project .settings -*~ +advtrains/locale/*.tr +advtrains/po/*~ diff --git a/advtrains/init.lua b/advtrains/init.lua index 053b3dd..a7fbc3f 100644 --- a/advtrains/init.lua +++ b/advtrains/init.lua @@ -22,8 +22,6 @@ Copyright (C) 2016-2020 Moritz Blei (orwell96) and contributors local lot = os.clock() minetest.log("action", "[advtrains] Loading...") -attrans = minetest.get_translator("advtrains") - --advtrains advtrains = {trains={}, player_to_train_mapping={}} @@ -200,6 +198,10 @@ advtrains.meseconrules = advtrains.fpath=minetest.get_worldpath().."/advtrains" +advtrains.poconvert = dofile(advtrains.modpath.."/poconvert.lua") +advtrains.poconvert.from_flat("advtrains") +attrans = minetest.get_translator("advtrains") + advtrains.speed = dofile(advtrains.modpath.."/speed.lua") dofile(advtrains.modpath.."/path.lua") @@ -231,7 +233,6 @@ end dofile(advtrains.modpath.."/lzb.lua") - --load/save -- backup variables, used if someone should accidentally delete a sub-mod diff --git a/advtrains/locale/README.md b/advtrains/locale/README.md index a54cb6c..3e94682 100644 --- a/advtrains/locale/README.md +++ b/advtrains/locale/README.md @@ -1,17 +1,12 @@ # Translations -**Please note that this document is outdated as transition to `.po` -files is currently in progress.** - Please read this document before working on any translations. -## Getting Started -If there is a translation file for your language (e.g. German), you can -edit the file directly. Please read [the documentation on the -translation file format][tr-format]. +Unlike many other mods, Advtrains uses `.po` files for localization, +which are then automatically converted to `.tr` files when the mod is +loaded. Therefore, please submit patches that edit the `.po` files. -Alternatively, Advtrains provides a script named `gui` that can be used -to, among other things, edit translation files. The script requires -Tcl/Tk 8.6, which is provided by most Linux distributions. +## Getting Started +The translation files can be edited like any other `.po` file. If the translation file for your language does not exist, create it by copying `template.txt` to `advtrains.XX.tr`, where `XX` is replaced by @@ -20,7 +15,7 @@ the language code. Feel free to use the [discussion mailing list][srht-discuss] if you have any questions regarding localization. -You can share your `.tr` file directly or [as a patch][gsm] to the [dev +You can share your `.po` file directly or [as a patch][gsm] to the [dev mailing list][srht-devel]. The latter is encouraged, but, unlike code changes, translation files sent directly are also accepted. @@ -62,6 +57,12 @@ halfwidth punctuation marks). However, do not leave any space between Han characters and Arabic numerals. ## Notes for developers +* The `update-translations.sh` script can be used to update the +translation files. However, please make sure to install the +`basic_trains` mod before running the script. +* Please make sure that the first argument to `S` (or `attrans`) _only_ +includes string literals without formatting or concatenation. This is +unfortunately a limitation of the `xgettext` utility. * Avoid word-by-word translations. * Avoid manipulating translated strings (except for concatenation). Use server-side translations if you have to modify the text sent to users. diff --git a/advtrains/locale/advtrains.de.tr b/advtrains/locale/advtrains.de.tr deleted file mode 100644 index d9fafc4..0000000 --- a/advtrains/locale/advtrains.de.tr +++ /dev/null @@ -1,146 +0,0 @@ -# textdomain: advtrains - -# Advtrains Core (unorganized) -This wagon is owned by @1, you can't destroy it.=Dieser Waggon gehört @1, Sie dürfen ihn nicht abbauen. -Warning: If you destroy this wagon, you only get some steel back! If you are sure, hold Sneak and left-click the wagon.=Warnung: Durch den Abbau des Waggons erhalten Sie nur etwas Stahl zurück. Nutzen Sie Schleichen+Linksklick, um dem Waggon abzubauen. -This position is protected!=Diese Position ist geschützt! -Can't place: not pointing at node=Es kann nicht platziert werden: Sie zeigen nicht auf einem Block. -Can't place: space occupied!=Es kann nicht platziert werden: diese Position ist besetzt. -Can't place: protected position!=Es kann nicht platziert werden: diese Position ist geschützt. -Can't place: Not enough slope items left (@1 required)=Es kann nicht platziert werden: Sie haben nicht genug Steigungsblöcke, es werden insgesamt @1 benötigt. -Can't place: There's no slope of length @1=Es kann nicht platziert werden: die Steigung der Länge @1 ist nicht definiert. -Can't place: no supporting node at upper end.=Es kann nicht platziert werden: es gibt keinen unterstützenden Block am Ende der Steigung. -Deprecated Track=ausrangiertes Gleis, nicht verwenden. -Can't get on: wagon full or doors closed!=Sie können nicht einsteigen: der Waggon ist voll oder die Türen sind geschlossen. -Use Sneak+rightclick to bypass closed doors!=Nutzen Sie Schleichen+Rechtsklick, um trotz geschlossener Türen einzusteigen. -Doors are closed! Use Sneak+rightclick to ignore the closed doors and get off!=Die Türen sind geschlossen. Nutzen Sie Schleichen+Rechtsklick, um trotz geschlossener Türen auszusteigen. -Access to @1=Zugang zu @1 -You do not have the @1 privilege.=Ihnen fehlt das „@1“-Privileg. -The wagon's inventory is not empty!=Das Inventar dieses Waggons ist nicht leer! -Position is occupied by a train.=Ein Zug steht an dieser Position. -There's a Track Circuit Break here.=Hier ist eine Gleisabschnittsgrenze (TCB). -There's a Signal Influence Point here.=Hier ist ein Signal-Beeinflussungspunkt. - -# Trackworker, rotation, adjustment -This node can't be rotated using the trackworker!=Dieser Block kann nicht mit dem Gleiswerkzeug gedreht werden. -This node can't be changed using the trackworker!=Dieser Block kann nicht mit dem Gleiswerkzeug bearbeitet werden. -This track can not be changed!=Dieses Gleis kann nicht geändert werden! -This track can not be rotated!=Dieses Gleis kann nicht gedreht werden! -This track can not be removed!=Dieses Gleis kann nicht entfernt werden! - -# ATC -ATC controller, unconfigured.=Nicht konfiguierte Zugbeeinflussungsgleis -ATC controller=Zugbeeinflussungsgleis -ATC controller, mode @1@nChannel: @2=Zugbeeinflussungsgleis in Betriebsart „@1“@nKanal: @2 -ATC controller, mode @1@nCommand: @2=Zugbeeinflussungsgleis in Betriebsart „@1“@nBefehl: @2 -Command=Befehl -Command (on)=Befehl (wenn aktiviert) -Digiline channel=Digiline-Kanal -ATC Kick command warning: Doors closed=ATC Kick command warning: Doors closed -ATC Kick command warning: Train moving=ATC Kick command warning: Train moving -ATC Reverse command warning: didn't reverse train, train moving!=Zugbeeinflussung: der Befehl „R“ wurde nicht ausgeführt, Zug in Bewegung! -ATC command syntax error: I statement not closed: @1=Zugbeeinflussung: Unvollständiger I-Befehl: @1 -ATC command parse error: Unknown command: @1=Zugbeeinflussung: Unbekannter Befehl: @1 - -# Coupling -Lock couples=Kupplungen sperren -You need to own at least one neighboring wagon to destroy this couple.=Sie müssen Besitzer eines angrenzenden Waggons sein, um hier abzukuppeln. -Buffer and Chain Coupler=Schraubenkupplung -Scharfenberg Coupler=Scharfenbergkupplung -Japanese Train Inter-Wagon Connection=Waggonzwischenverbindung Japanischer Personenzüge -Can not couple: The couplers of the trains do not match (@1 and @2).=Die Kupplungen der Züge passen nicht zueinander (@1 und @2). -You are not allowed to couple trains without the train_operator privilege.=Sie dürfen ohne das „train_builder“-Privileg keine Züge ankuppeln. - -# Clipboard -The track you are trying to place the wagon on is not long enough!=Das Gleis, auf dem der Waggon platziert werden woll, ist zu kurz. -The clipboard couldn't access the metadata. Paste failed.=Wegen des fehlgeschlagenen Zugriffs auf die Metadaten konnte eine Kopie des Zuges nicht eingefügt werden. -The clipboard couldn't access the metadata. Copy failed.=Wegen des fehlgeschlagenen Zugriffs auf die Metadaten konnte der Zug nicht kopiert werden. -The clipboard is empty.=Das Clipboard ist leer. -Back of train would end up off track, cancelling.=Der hinterer Teil dez Zuges wäre nicht auf dem Gleis. -No such lua entity!=Sie zeigen nicht auf einem Objekt, das mit diesem Werkzeug kopiert werden kann. -No such wagon: @1=Es gibt keinen mit „@1“ identifizierbaren Waggon. -No such train: @1=Es gibt keinen mit „@1“ identifizierbaren Zug. -Train copied!=Der Zug wurde Kopiert. - -# Protection -You are not allowed to build tracks without the track_builder privilege.=Sie dürfen ohne das „track_builder“-Privileg kein Gleis bauen. -You are not allowed to build near tracks without the track_builder privilege.=Sie dürfen ohne das „track_builder“-Privileg nicht in der Nähe von Gleisen bauen. -You are not allowed to build tracks at this protected position.=Sie dürfen an geschützten Stellen kein Gleis bauen. -You are not allowed to build near tracks at this protected position.=Sie dürfen an geschützten Stellen nicht in der Nähe von Gleisen bauen. -You are not allowed to operate turnouts and signals without the railway_operator privilege.=Sie dürfen ohne das „railway_operator“-Privileg keine Bahnanlage operieren. - -# Train HUD/Formspecs -Speed:=Geschw.: -Target:=Zielges.: -Show Inventory=Inventar Zeigen -Select seat:=Wählen Sie einen Sitzplatz aus: -Wagon properties=Waggon-Einstellungen -Save wagon properties=Waggon-Einstellungen speichern -Text displayed outside on train=Äußere Anzeige -Text displayed inside train=Innere Anzeige -Line=Linie -Routingcode=Routingcode -Get off=Aussteigen -Get off (forced)=Ausstieg zwingen -(Doors closed)=(Türen geschlossen) - -# General -Save=Speichern - -# Line automation -Station Code=Code der Haltestelle -Station Name=Name der Haltestelle -Door Delay=Zeit für die Türschließung -Door Side=Door Side -Dep. Speed=Zielgeschwindigkeit bei Abfahrt -Stop Time=Wartezeit - -# Items -Track Worker Tool@n@nLeft-click: change rail type (straight/curve/switch)@nRight-click: rotate rail/bumper/signal/etc.=Gleiswerkzeug@n@nLinksklick: Gleistyp ändern, Rechtsklick: Objekt drehen. -Passive Component Naming Tool@n@nRight-click to name a passive component.=PC-Benennungswerkzeug@n@nRechtsklick zur Benennung der passiven Komponente -Train copy/paste tool@n@nLeft-click: copy train@nRight-click: paste train=Werkzeug zur Erstellung von Zugkopien@n@nLinksklick: Zug ins Clipboard kopieren@nRight-click: Kopierten Zug einfügen -Track=Gleis -Perpendicular Diamond Crossing Track=Kreuzung mit zueinander orthogonalen Gleisen -Diagonal Diamond Crossing Track=Diagonale Gleiskreuzung -90+Angle Diamond Crossing Track=Kreuzung mit einem achsenparallelen Gleis -Y-turnout=Y-Weiche -3-way turnout=Dreiwegweiche -Unloading Track=Abladungsgleis -Loading Track=Beladungsgleis -Bumper=Prellbock -Detector Rail=Detektorgleis -@1 Slope=@1 Steigung -@1 Platform (low)=Niedriger @1-Bahnsteig -@1 Platform (high)=Hoher @1-Bahnsteig -@1 Platform (low, 45 degree)=Niedriger @1-Bahnsteig (45°) -@1 Platform (45 degree)=Hoher @1-Bahnsteig (45°) -Lampless Signal=Mechanisches Signal -Signal=Lichtsignal -Wallmounted Signal (l)=An der linken Seite montiertes Signal -Wallmounted Signal (r)=An der rechten Seite montiertes Signal -Wallmounted Signal (t)=An der Decke montiertes Signal -Andrew's Cross=Andrew's Cross -Boiler=Boiler -driver's cab=driver's cab -Wheel=Wheel -Chimney=Chimney - -# Seats -Default Seat=Standardsitzplatz -Default Seat (driver stand)=Standardsitzplatz (Führerstand) -Driver stand=Führerstand -Driver Stand (left)=Führerstand Links -Driver Stand (right)=Führerstand Rechts - -# Wagon/engine types -Industrial Train Engine=Industrielle Lokomotive -Big Industrial Train Engine=Große Industrielle Lokomotive -Industrial tank wagon=Tankwaggon -Industrial wood wagon=Holztransportwaggon -Japanese Train Engine=Japanische Personenzug-Lokomotive -Japanese Train Wagon=Japanischer Personenzug-Passagierwaggon -Steam Engine=Dampflokomotive -Detailed Steam Engine=detaillierte Dampflokomotive -Passenger Wagon=Passagierwaggon -Box Wagon=Güterwaggon -Subway Passenger Wagon=U-Bahn-Waggon diff --git a/advtrains/locale/advtrains.fr.tr b/advtrains/locale/advtrains.fr.tr deleted file mode 100644 index 0dd6d00..0000000 --- a/advtrains/locale/advtrains.fr.tr +++ /dev/null @@ -1,146 +0,0 @@ -# textdomain: advtrains - -# Advtrains Core (unorganized) -This wagon is owned by @1, you can't destroy it.=Ce wagon est la propriété de @1, vous ne pouvez pas le détruire. -Warning: If you destroy this wagon, you only get some steel back! If you are sure, hold Sneak and left-click the wagon.=Attention: Si vous détruisez ce wagon, vous ne récupérerez que de la ferraille ! Si vous êtes sûr de vous, appuyez la touche "Marcher lentement (Sneak)" et Clic-Gauche. -This position is protected!=Cet emplacement est protégé ! -Can't place: not pointing at node=Placement impossible : ne pointe pas un nœud -Can't place: space occupied!=Placement impossible : espace occupé -Can't place: protected position!=Placement impossible : emplacement protégé -Can't place: Not enough slope items left (@1 required)=Placement impossible : quantité insuffisante de voie pentue (@1 manquant) -Can't place: There's no slope of length @1=Placement impossible : il n'y a pas de voie pentue de longueur @1 -Can't place: no supporting node at upper end.=Placement impossible : pas de nœud d'appui à l'extrémité supérieure -Deprecated Track=Voie déconseillée -Can't get on: wagon full or doors closed!=Embarquement impossible : le wagon est plein ou ses portes sont closes ! -Use Sneak+rightclick to bypass closed doors!=Utilisez "Marcher lentement (Sneak)" et Clic-Droit pour franchir les portes closes ! -Doors are closed! Use Sneak+rightclick to ignore the closed doors and get off!=Portes closes ! Utilisez "Marcher lentement (Sneak)" et Clic-Droit pour franchir les portes et débarquer ! -Access to @1=Accès à @1 -You do not have the @1 privilege.=Vous ne possédez pas le privilège "@1". -The wagon's inventory is not empty!=Le stock de ce wagon n'est pas vide ! -Position is occupied by a train.=Cet emplacement est occupé par un train. -There's a Track Circuit Break here.=Il y a un "Track Circuit Break" ici. -There's a Signal Influence Point here.=Il y a un "Signal Influence Point" ici. - -# Trackworker, rotation, adjustment -This node can't be rotated using the trackworker!=Ce nœud ne peut être tourné avec l'outil "Trackworker" ! -This node can't be changed using the trackworker!=Ce nœud ne peut être modifié avec l'outil "Trackworker" ! -This track can not be changed!=Cette voie ne peut pas être modifiée ! -This track can not be rotated!=Cette voie ne peut pas être tournée ! -This track can not be removed!=Cette voie ne peut pas être enlevée ! - -# ATC -ATC controller, unconfigured.=Controlleur ATC, non-configuré -ATC controller=Controlleur ATC -ATC controller, mode @1@nChannel: @2=Controlleur ATC, mode @1@nCanal : @2 -ATC controller, mode @1@nCommand: @2=Controlleur ATC, mode @1@nCommande : @2 -Command=Commande -Command (on)=Commande (marche) -Digiline channel=Canal Digiline -ATC Kick command warning: Doors closed=ATC Kick command warning: Doors closed -ATC Kick command warning: Train moving=ATC Kick command warning: Train moving -ATC Reverse command warning: didn't reverse train, train moving!=Attention : Commande ATC de renversement impossible car le train se déplace ! -ATC command syntax error: I statement not closed: @1=Erreur de syntaxe de commande ATC : instruction "I" incomplète : @1 -ATC command parse error: Unknown command: @1=Erreur d'analyse de commande ATC : Commande inconnue : @1 - -# Coupling -Lock couples=Verrouiller l'accouplement -You need to own at least one neighboring wagon to destroy this couple.=Vous devez être propriétaire d'au moins un wagon voisin pour supprimer cet attelage. -Buffer and Chain Coupler=Attelage à tampon et vis -Scharfenberg Coupler=Attelage Scharfenberg -Japanese Train Inter-Wagon Connection=Passage inter-voiture de train Japonais -Can not couple: The couplers of the trains do not match (@1 and @2).=Accouplement impossible: les attelages des trains ne concordent pas (@1 et @2). -You are not allowed to couple trains without the train_operator privilege.=You are not allowed to couple trains without the train_operator privilege. - -# Clipboard -The track you are trying to place the wagon on is not long enough!=La voie sur laquelle vous tentez de placer le wagon est trop courte ! -The clipboard couldn't access the metadata. Paste failed.=Le presse-papier ne peut accéder aux métadonnées. Échec du collage. -The clipboard couldn't access the metadata. Copy failed.=Le presse-papier ne peut accéder aux métadonnées. Échec de la copie. -The clipboard is empty.=Le presse-papier est vide. -Back of train would end up off track, cancelling.=La fin du train serait hors voie : annulation. -No such lua entity!=Pas de telle entité lua ! -No such wagon: @1=Pas de tel wagon : @1 -No such train: @1=Pas de tel train : @1 -Train copied!=Train copié ! - -# Protection -You are not allowed to build tracks without the track_builder privilege.=Vous ne pouvez pas construire une voie sans le privilège "track_builder" -You are not allowed to build near tracks without the track_builder privilege.=Vous ne pouvez pas construire à proximité d'une voie sans le privilège "track_builder" (?) -You are not allowed to build tracks at this protected position.=Vous ne pouvez pas construire une voie à cet emplacement protégé -You are not allowed to build near tracks at this protected position.=Vous ne pouvez pas construire à proximité d'une voie à cet emplacement protégé -You are not allowed to operate turnouts and signals without the railway_operator privilege.=Vous ne pouvez pas actionner les aiguillages ou les signaux (privilège "railway_operator" manquant) - -# Train HUD/Formspecs -Speed:=Vitesse : -Target:=Destination : -Show Inventory=Montrer le stock -Select seat:=Choisir le siège -Wagon properties=Propriétés du wagon -Save wagon properties=Sauvegarder les propriétés du wagon -Text displayed outside on train=Texte affiché à l'extérieur du train -Text displayed inside train=Texte affiché à l'intérieur du train -Line=Ligne -Routingcode=Code de routage -Get off=Débarquer -Get off (forced)=Débarquer (de force) -(Doors closed)=(Portes closes) - -# General -Save=Sauvegarder - -# Line automation -Station Code=Code de Station -Station Name=Nom de Station -Door Delay=Durée d'ouverture des portes -Door Side=Door Side -Dep. Speed=Vitesse de départ -Stop Time=Durée d'arrêt - -# Items -Track Worker Tool@n@nLeft-click: change rail type (straight/curve/switch)@nRight-click: rotate rail/bumper/signal/etc.=Outil "Trackworker"@n@nClic-Gauche : change le type de rail (droit/courbé/aiguillage)@n@nClic-Droit : tourne le rail/butoir/signal/etc... -Passive Component Naming Tool@n@nRight-click to name a passive component.=Outil de nommage de composant passif@n@nClic-Droit pour nommer un composant passif. -Train copy/paste tool@n@nLeft-click: copy train@nRight-click: paste train=Outil de copie/collage de train@n@nClic-Gauche : copie@n@nClic-Droit : collage -Track=Voie -Perpendicular Diamond Crossing Track=Croisement perpendiculaire -Diagonal Diamond Crossing Track=Croisement diagonal -90+Angle Diamond Crossing Track=Croisement perpendiculo-diagonal -Y-turnout=Embranchement en Y -3-way turnout=Embranchement triple -Unloading Track=Voie de Déchargement -Loading Track=Voie de Chargement -Bumper=Heurtoir -Detector Rail=Voie détectrice -@1 Slope=Pente @1 -@1 Platform (low)=Quai @1 (bas) -@1 Platform (high)=Quai @1 (haut) -@1 Platform (low, 45 degree)=Quai @1 (bas, 45°) -@1 Platform (45 degree)=Quai @1 (haut, 45°) -Lampless Signal=Sémaphore -Signal=Signal -Wallmounted Signal (l)=Signal mural (gauche) -Wallmounted Signal (r)=Signal mural (droit) -Wallmounted Signal (t)=Signal mural (plafond) -Andrew's Cross=Croix de Saint André -Boiler=Chaudière à vapeur -driver's cab=Cabine de pilotage -Wheel=Roue -Chimney=Cheminée - -# Seats -Default Seat=Siège par défaut -Default Seat (driver stand)=Siège par défaut (poste de pilotage) -Driver stand=Poste de pilotage -Driver Stand (left)=Poste de pilotage (gauche) -Driver Stand (right)=Poste de pilotage (droit) - -# Wagon/engine types -Industrial Train Engine=Locomotive industrielle -Big Industrial Train Engine=Grosse locomotive industrielle -Industrial tank wagon=Wagon-citerne industriel -Industrial wood wagon=Wagon grumier industriel -Japanese Train Engine=Motrice Japonaise -Japanese Train Wagon=Voiture Japonaise -Steam Engine=Locomotive à vapeur -Detailed Steam Engine=Locomotive à vapeur complexe -Passenger Wagon=Voiture passager -Box Wagon=Wagon de frêt -Subway Passenger Wagon=Voiture de Métropolitain diff --git a/advtrains/locale/advtrains.zh_CN.tr b/advtrains/locale/advtrains.zh_CN.tr deleted file mode 100644 index 6ed4887..0000000 --- a/advtrains/locale/advtrains.zh_CN.tr +++ /dev/null @@ -1,146 +0,0 @@ -# textdomain: advtrains - -# Advtrains Core (unorganized) -This wagon is owned by @1, you can't destroy it.=这是 @1 的车厢,您不能摧毁它。 -Warning: If you destroy this wagon, you only get some steel back! If you are sure, hold Sneak and left-click the wagon.=警告:如果您摧毁此车厢,您只能拿到一些钢方块。如果您确定要摧毁这节车厢,请按潜行键并左键单击此车厢。 -This position is protected!=这里已被保护。 -Can't place: not pointing at node=无法放置:您没有选择任何方块。 -Can't place: space occupied!=无法放置:此区域已被占用。 -Can't place: protected position!=无法放置:此区域已被保护。 -Can't place: Not enough slope items left (@1 required)=无法放置:您没有足够的铁路斜坡放置工具 (您总共需要@1个) -Can't place: There's no slope of length @1=无法放置:advtrains 不支持长度为@1米的斜坡。 -Can't place: no supporting node at upper end.=无法放置:较高端没有支撑方块。 -Deprecated Track=请不要使用 -Can't get on: wagon full or doors closed!=无法上车:车门已关闭或车厢已满。 -Use Sneak+rightclick to bypass closed doors!=请使用潜行+右键上车。 -Doors are closed! Use Sneak+rightclick to ignore the closed doors and get off!=车门已关闭,请使用潜行+右键单击下车。 -Access to @1=可前往@1 -You do not have the @1 privilege.=您没有“@1”权限。 -The wagon's inventory is not empty!=The wagon's inventory is not empty! -Position is occupied by a train.=Position is occupied by a train. -There's a Track Circuit Break here.=There's a Track Circuit Break here. -There's a Signal Influence Point here.=There's a Signal Influence Point here. - -# Trackworker, rotation, adjustment -This node can't be rotated using the trackworker!=您不能使用铁路调整工具旋转这个方块。 -This node can't be changed using the trackworker!=您不能使用铁路调整工具调整这个方块。 -This track can not be changed!=您不能调整这段轨道。 -This track can not be rotated!=您不能旋转这段轨道。 -This track can not be removed!=您不能移除这段轨道。 - -# ATC -ATC controller, unconfigured.=ATC 控制器 (未配置) -ATC controller=ATC 控制器 -ATC controller, mode @1@nChannel: @2=ATC 控制器@n模式:@1@n频道:@2 -ATC controller, mode @1@nCommand: @2=ATC 控制器@n模式:@1@n命令:@2 -Command=命令 -Command (on)=命令 (激活时) -Digiline channel=Digiline 频道 -ATC Kick command warning: Doors closed=ATC Kick command warning: Doors closed -ATC Kick command warning: Train moving=ATC Kick command warning: Train moving -ATC Reverse command warning: didn't reverse train, train moving!=ATC 警告:未执行“R”命令,火车在移动 -ATC command syntax error: I statement not closed: @1=ATC 语法错误:“I”命令不完整:@1 -ATC command parse error: Unknown command: @1=ATC 语法错误:未知命令:@1 - -# Coupling -Lock couples=锁定连接处 -You need to own at least one neighboring wagon to destroy this couple.=您必须至少拥有其中一节车厢才能分开这两节车厢。 -Buffer and Chain Coupler=链式车钩 -Scharfenberg Coupler=Scharfenberg 式车钩 -Japanese Train Inter-Wagon Connection=日本火车车钩 -Can not couple: The couplers of the trains do not match (@1 and @2).=您无法连接这两节车厢:这两节车厢使用不同的车钩 (@1和@2)。 -You are not allowed to couple trains without the train_operator privilege.=您没有“train_operator”权限,不能连接这两节车厢。 - -# Clipboard -The track you are trying to place the wagon on is not long enough!=轨道太短。 -The clipboard couldn't access the metadata. Paste failed.=无法粘贴:剪贴板无法访问元数据。 -The clipboard couldn't access the metadata. Copy failed.=无法复制:剪贴板无法访问元数据。 -The clipboard is empty.=剪贴板是空的。 -Back of train would end up off track, cancelling.=火车后部不在轨道上。 -No such lua entity!=您没有指向一个可以用火车复制工具复制的物体。 -No such wagon: @1=ID 为“@1”的车厢不存在。 -No such train: @1=ID 为“@1”的列车不存在。 -Train copied!=已复制 - -# Protection -You are not allowed to build tracks without the track_builder privilege.=您没有“train_operator”权限,不能在这里建造铁路。 -You are not allowed to build near tracks without the track_builder privilege.=您没有“train_operator”权限,不能在铁路附近建任何东西。 -You are not allowed to build tracks at this protected position.=这里已被保护,您不能在这里建造铁路。 -You are not allowed to build near tracks at this protected position.=这里已被保护,您不能在这里的铁路附近建任何东西。 -You are not allowed to operate turnouts and signals without the railway_operator privilege.=您没有“railway_operator”权限,不能控制铁路设施。 - -# Train HUD/Formspecs -Speed:=速度 -Target:=目标速度 -Show Inventory=显示物品栏 -Select seat:=请选择座位 -Wagon properties=车厢属性 -Save wagon properties=保存车厢属性 -Text displayed outside on train=车厢外部显示 -Text displayed inside train=车厢内部显示 -Line=火车线路 -Routingcode=路由码 -Get off=下车 -Get off (forced)=强制下车 -(Doors closed)=(车门已关闭) - -# General -Save=保存 - -# Line automation -Station Code=车站代码 -Station Name=车站名称 -Door Delay=车门关闭时间 -Door Side=Door Side -Dep. Speed=出发速度 -Stop Time=停站时间 - -# Items -Track Worker Tool@n@nLeft-click: change rail type (straight/curve/switch)@nRight-click: rotate rail/bumper/signal/etc.=铁路调整工具@n@n左键单击:切换轨道类型@n右键单击:旋转方块 -Passive Component Naming Tool@n@nRight-click to name a passive component.=被动元件命名工具@n@n右键单击命名所选元件 -Train copy/paste tool@n@nLeft-click: copy train@nRight-click: paste train=火车复制工具@n@n左键单击:复制@n右键单击:粘帖 -Track=轨道 -Perpendicular Diamond Crossing Track=垂直交叉轨道 -Diagonal Diamond Crossing Track=交叉轨道 -90+Angle Diamond Crossing Track=交叉轨道 (其中一条轨道与坐标轴平行) -Y-turnout=对称道岔 -3-way turnout=三开道岔 -Unloading Track=卸货轨道 -Loading Track=装货轨道 -Bumper=保险杠 -Detector Rail=探测轨道 -@1 Slope=@1斜坡 -@1 Platform (low)=较低的@1站台 -@1 Platform (high)=较高的@1站台 -@1 Platform (low, 45 degree)=较低的@1站台 (45°) -@1 Platform (45 degree)=较高的@1站台 (45°) -Lampless Signal=臂板信号机 -Signal=信号灯 -Wallmounted Signal (l)=壁挂式信号灯 (左侧) -Wallmounted Signal (r)=壁挂式信号灯 (右侧) -Wallmounted Signal (t)=悬挂式信号灯 -Andrew's Cross=铁路道口信号灯 -Boiler=锅炉 -driver's cab=驾驶室 -Wheel=车轮 -Chimney=烟囱 - -# Seats -Default Seat=默认座位 -Default Seat (driver stand)=默认座位 (司机座位) -Driver stand=司机座位 -Driver Stand (left)=左侧司机座位 -Driver Stand (right)=右侧司机座位 - -# Wagon/engine types -Industrial Train Engine=工业用火车头 -Big Industrial Train Engine=大型工业用火车头 -Industrial tank wagon=液体运输车厢 -Industrial wood wagon=木材运输车厢 -Japanese Train Engine=高速列车车头 -Japanese Train Wagon=高速列车车厢 -Steam Engine=蒸汽机车 -Detailed Steam Engine=精细的蒸汽机车 -Passenger Wagon=客车 -Box Wagon=货运车厢 -Subway Passenger Wagon=地铁车厢 diff --git a/advtrains/locale/advtrains.zh_TW.tr b/advtrains/locale/advtrains.zh_TW.tr deleted file mode 100644 index 37cce79..0000000 --- a/advtrains/locale/advtrains.zh_TW.tr +++ /dev/null @@ -1,146 +0,0 @@ -# textdomain: advtrains - -# Advtrains Core (unorganized) -This wagon is owned by @1, you can't destroy it.=這是 @1 的車廂,您不能摧毀它。 -Warning: If you destroy this wagon, you only get some steel back! If you are sure, hold Sneak and left-click the wagon.=警告:如果您摧毀此車廂,您只能拿到一些鋼方塊。如果您確定要摧毀這節車廂,請按潛行鍵並左鍵單擊此車廂。 -This position is protected!=這裡已被保護。 -Can't place: not pointing at node=無法放置:您沒有選擇任何方塊。 -Can't place: space occupied!=無法放置:此區域已被佔用。 -Can't place: protected position!=無法放置:此區域已被保護。 -Can't place: Not enough slope items left (@1 required)=無法放置:您沒有足夠的鐵路斜坡放置工具 (您總共需要@1個) -Can't place: There's no slope of length @1=無法放置:advtrains 不支援長度為@1米的斜坡。 -Can't place: no supporting node at upper end.=無法放置:較高階沒有支撐方塊。 -Deprecated Track=請不要使用 -Can't get on: wagon full or doors closed!=無法上車:車門已關閉或車廂已滿。 -Use Sneak+rightclick to bypass closed doors!=請使用潛行+右鍵上車。 -Doors are closed! Use Sneak+rightclick to ignore the closed doors and get off!=車門已關閉,請使用潛行+右鍵單擊下車。 -Access to @1=可前往@1 -You do not have the @1 privilege.=您沒有「@1」許可權。 -The wagon's inventory is not empty!=The wagon's inventory is not empty! -Position is occupied by a train.=Position is occupied by a train. -There's a Track Circuit Break here.=There's a Track Circuit Break here. -There's a Signal Influence Point here.=There's a Signal Influence Point here. - -# Trackworker, rotation, adjustment -This node can't be rotated using the trackworker!=您不能使用鐵路調整工具旋轉這個方塊。 -This node can't be changed using the trackworker!=您不能使用鐵路調整工具調整這個方塊。 -This track can not be changed!=您不能調整這段軌道。 -This track can not be rotated!=您不能旋轉這段軌道。 -This track can not be removed!=您不能移除這段軌道。 - -# ATC -ATC controller, unconfigured.=ATC 控制器 (未配置) -ATC controller=ATC 控制器 -ATC controller, mode @1@nChannel: @2=ATC 控制器@n模式:@1@n頻道:@2 -ATC controller, mode @1@nCommand: @2=ATC 控制器@n模式:@1@n命令:@2 -Command=命令 -Command (on)=命令 (啟用時) -Digiline channel=Digiline 頻道 -ATC Kick command warning: Doors closed=ATC Kick command warning: Doors closed -ATC Kick command warning: Train moving=ATC Kick command warning: Train moving -ATC Reverse command warning: didn't reverse train, train moving!=ATC 警告:未執行「R」命令,火車在移動 -ATC command syntax error: I statement not closed: @1=ATC 語法錯誤:「I」命令不完整:@1 -ATC command parse error: Unknown command: @1=ATC 語法錯誤:未知命令:@1 - -# Coupling -Lock couples=鎖定連結處 -You need to own at least one neighboring wagon to destroy this couple.=您必須至少擁有其中一節車廂才能分開這兩節車廂。 -Buffer and Chain Coupler=鏈式連結器 -Scharfenberg Coupler=Scharfenberg 式連結器 -Japanese Train Inter-Wagon Connection=日本火車連結器 -Can not couple: The couplers of the trains do not match (@1 and @2).=您無法連結這兩節車廂:這兩節車廂使用不同的連結器 (@1和@2)。 -You are not allowed to couple trains without the train_operator privilege.=您沒有「train_operator」許可權,不能連結這兩節車廂。 - -# Clipboard -The track you are trying to place the wagon on is not long enough!=軌道太短。 -The clipboard couldn't access the metadata. Paste failed.=無法貼上:剪貼簿無法訪問元資料。 -The clipboard couldn't access the metadata. Copy failed.=無法複製:剪貼簿無法訪問元資料。 -The clipboard is empty.=剪貼簿是空的。 -Back of train would end up off track, cancelling.=火車後部不在軌道上。 -No such lua entity!=您沒有指向一個可以用火車複製工具複製的物體。 -No such wagon: @1=ID 為「@1」的車廂不存在。 -No such train: @1=ID 為「@1」的列車不存在。 -Train copied!=已複製 - -# Protection -You are not allowed to build tracks without the track_builder privilege.=您沒有「train_operator」許可權,不能在這裡建造鐵路。 -You are not allowed to build near tracks without the track_builder privilege.=您沒有「train_operator」許可權,不能在鐵路附近建任何東西。 -You are not allowed to build tracks at this protected position.=這裡已被保護,您不能在這裡建造鐵路。 -You are not allowed to build near tracks at this protected position.=這裡已被保護,您不能在這裡的鐵路附近建任何東西。 -You are not allowed to operate turnouts and signals without the railway_operator privilege.=您沒有「railway_operator」許可權,不能控制鐵路設施。 - -# Train HUD/Formspecs -Speed:=速度 -Target:=目標速度 -Show Inventory=顯示物品欄 -Select seat:=請選擇座位 -Wagon properties=車廂屬性 -Save wagon properties=儲存車廂屬性 -Text displayed outside on train=車廂外部顯示 -Text displayed inside train=車廂內部顯示 -Line=火車線路 -Routingcode=路由碼 -Get off=下車 -Get off (forced)=強制下車 -(Doors closed)=(車門已關閉) - -# General -Save=儲存 - -# Line automation -Station Code=車站碼 -Station Name=車站名稱 -Door Delay=車門關閉時間 -Door Side=Door Side -Dep. Speed=出發速度 -Stop Time=停站時間 - -# Items -Track Worker Tool@n@nLeft-click: change rail type (straight/curve/switch)@nRight-click: rotate rail/bumper/signal/etc.=鐵路調整工具@n@n左鍵單擊:切換軌道型別@n右鍵單擊:旋轉方塊 -Passive Component Naming Tool@n@nRight-click to name a passive component.=被動元件命名工具@n@n右鍵單擊命名所選元件 -Train copy/paste tool@n@nLeft-click: copy train@nRight-click: paste train=火車複製工具@n@n左鍵單擊:複製@n右鍵單擊:粘帖 -Track=軌道 -Perpendicular Diamond Crossing Track=垂直交叉軌道 -Diagonal Diamond Crossing Track=交叉軌道 -90+Angle Diamond Crossing Track=交叉軌道 (其中一條軌道與座標軸平行) -Y-turnout=對稱道岔 -3-way turnout=三開道岔 -Unloading Track=卸貨軌道 -Loading Track=裝貨軌道 -Bumper=保險槓 -Detector Rail=探測軌道 -@1 Slope=@1斜坡 -@1 Platform (low)=較低的@1月臺 -@1 Platform (high)=較高的@1月臺 -@1 Platform (low, 45 degree)=較低的@1月臺 (45°) -@1 Platform (45 degree)=較高的@1月臺 (45°) -Lampless Signal=臂木式號誌機 -Signal=色燈號誌機 -Wallmounted Signal (l)=壁掛式色燈號誌機 (左側) -Wallmounted Signal (r)=壁掛式色燈號誌機 (右側) -Wallmounted Signal (t)=懸掛式色燈號誌機 -Andrew's Cross=平交道號誌燈 -Boiler=鍋爐 -driver's cab=駕駛室 -Wheel=車輪 -Chimney=煙囪 - -# Seats -Default Seat=預設座位 -Default Seat (driver stand)=預設座位 (司機座位) -Driver stand=司機座位 -Driver Stand (left)=左側司機座位 -Driver Stand (right)=右側司機座位 - -# Wagon/engine types -Industrial Train Engine=工業用火車頭 -Big Industrial Train Engine=大型工業用火車頭 -Industrial tank wagon=液體運輸車廂 -Industrial wood wagon=木材運輸車廂 -Japanese Train Engine=高速列車車頭 -Japanese Train Wagon=高速列車車廂 -Steam Engine=蒸汽機車 -Detailed Steam Engine=精細的蒸汽機車 -Passenger Wagon=客車 -Box Wagon=貨運車廂 -Subway Passenger Wagon=地鐵車廂 diff --git a/advtrains/locale/gui b/advtrains/locale/gui deleted file mode 100755 index 7f455e4..0000000 --- a/advtrains/locale/gui +++ /dev/null @@ -1,638 +0,0 @@ -#!/usr/bin/tclsh -package require Tk - -# Auxiliary functions -proc maybe_lindex {lst idx fallback} { - set val [lindex $lst $idx] - if {$val eq {}} { - return $fallback - } else { - return $val - } -} - -proc firstupper {str} { - return [string cat [string toupper [string index $str 0]] [string range $str 1 end]] -} - -# CLI arguments -# NOTE: This will likely be changed in the future -set translationDomain [maybe_lindex $argv 0 "advtrains"] -set translationDir [maybe_lindex $argv 1 "."] - -# Translation file I/O, etc - -set translationTemplatePath [file join $translationDir "template.txt"] - -proc translationFilePaths {} { - global translationDir translationDomain - return [glob -path [file join $translationDir $translationDomain] ".*.tr"] -} - -proc readTranslationTemplate {} { - global translationTemplate translationTemplatePath - set translationTemplate [list] - set handle [open $translationTemplatePath "r"] - fconfigure $handle -translation lf - while {[gets $handle line] >= 0} { - if {$line eq ""} { - lappend translationTemplate $line - } elseif {[string match {#*} $line]} { - lappend translationTemplate $line - } elseif {[regexp {^(.+[^@])=.+$} $line x str]} { - lappend translationTemplate $str - } - } - close $handle -} - -proc readTranslationFiles {} { - global translationData translationLangs - array set translationData [list] - set translationLangs [list] - foreach fn [translationFilePaths] { - if {[regexp {\.([^.]+)\.tr$} $fn x lang]} { - set handle [open $fn "r"] - fconfigure $handle -translation lf - while {[gets $handle line] >= 0} { - if {[regexp {^([^#].+[^@])=(.+)$} $line x ori tr]} { - set translationData($lang,$ori) $tr - } - } - lappend translationLangs $lang - close $handle - } - } - set translationLangs [lsort $translationLangs] -} - -proc readTranslations {} { - readTranslationTemplate - readTranslationFiles -} - -proc writeTranslationTemplate {} { - global translationTemplate translationTemplatePath - set handle [open $translationTemplatePath "w"] - fconfigure $handle -translation lf - foreach line $translationTemplate { - if {$line eq ""} { - puts $handle "" - } elseif {[string match {#*} $line]} { - puts $handle $line - } else { - puts $handle "$line=$line" - } - } - close $handle -} - -proc writeTranslationFiles {} { - global translationDir translationDomain translationData translationLangs translationTemplate - foreach lang $translationLangs { - set handle [open [file join $translationDir "$translationDomain.$lang.tr"] "w"] - fconfigure $handle -translation lf - foreach i $translationTemplate { - if {$i eq ""} { - puts $handle "" - } elseif {[string match {#*} $i]} { - puts $handle $i - } else { - puts $handle [format "%s=%s" $i [getTranslationString $lang $i]] - } - } - close $handle - } -} - -proc writeTranslations {} { - writeTranslationTemplate - writeTranslationFiles -} - -proc hasTranslationString {lang str} { - return [expr {[getTranslationString $lang $str] ne $str}] -} - -proc maybeGetTranslationString {lang str} { - set tr [getTranslationString $lang $str] - if {$tr eq $str} { - return {} - } else { - return $tr - } -} - -proc getTranslationString {lang str} { - global translationData - if {[info exists translationData($lang,$str)]} { - return $translationData($lang,$str) - } else { - return $str - } -} - -proc setTranslationString {lang ori tr} { - global translationData - set translationData($lang,$ori) $tr -} - -proc rewordTranslationString {old new} { - global translationData translationLangs - foreach lang $translationLangs { - if {[hasTranslationString $lang $old]} { - setTranslationString $lang $new [getTranslationString $lang $old] - } else { - setTranslationString $lang $new $new - } - } -} - -# GUI helpers -proc gAddTab {basename title elems dummies} { - global gMainNotebook - gAddFrame $basename $elems $dummies - $gMainNotebook add "$gMainNotebook.$basename" -text $title -} - -proc gAddFrame {basename elems dummies} { - global gMainNotebook - set varbase [string cat "g" [firstupper $basename]] - set varname "${varbase}Frame" - set pathname "$gMainNotebook.$basename" - global $varname - set $varname $pathname - ttk::frame $pathname -padding 5 - foreach i $elems { - set varname [string cat $varbase [firstupper $i]] - global $varname - set $varname "$pathname.$i" - } - foreach i $dummies { - set varname [string cat $varbase [firstupper $i]] - global $varname - set $varname {} - } -} - -proc gReloadTranslations {} { - readTranslations - gTrLoadTranslations - gTmLoadTranslations -} - -proc gAddMenu {varname parent menuname entries} { - global $varname - set path "${parent}.${menuname}" - set $varname $path - $parent configure -menu [menu $path -tearoff false] - foreach i $entries { - $path add {*}$i - } - return $parent -} -set gMenuItemNotImplemented [list command -state disabled -label "(Not implemented)"] - -proc gNotImplemented {args} { - tk_messageBox -message "Not implemented" -icon error -type ok -} - -# Main window - -set gMainFrame ".f" -set gMainFrameWidgetCount 0 -foreach i [list readBtn writeBtn notebookTopSeparator notebook] { - set [string cat "gMain" [firstupper $i]] "$gMainFrame.$i" -} - -wm title . "Advtrains Translation File Editor" -grid rowconfigure . 0 -weight 1 -grid columnconfigure . 0 -weight 1 - -ttk::frame $gMainFrame -grid $gMainFrame -column 0 -row 0 -sticky nsew -grid rowconfigure $gMainFrame 2 -weight 1 - -foreach i [list \ - [ttk::button $gMainReadBtn -text "Reload translation files" -command gReloadTranslations] \ - [ttk::button $gMainWriteBtn -text "Write changes" -command writeTranslations] \ -] { - grid $i -column $gMainFrameWidgetCount -row 0 -sticky ns - incr gMainFrameWidgetCount -} - -grid columnconfigure $gMainFrame $gMainFrameWidgetCount -weight 1 - -ttk::separator $gMainNotebookTopSeparator -orient horizontal -grid $gMainNotebookTopSeparator -column 0 -row 1 -columnspan [expr {1+$gMainFrameWidgetCount}] -sticky ew - -ttk::notebook $gMainNotebook -grid $gMainNotebook -column 0 -row 2 -columnspan [expr {1+$gMainFrameWidgetCount}] -sticky nsew - -# Translation Manager -# FIXME?: it seems like Tcl requires -textvariable globals to be set first before they are accessible - -gAddTab tr "Translations" \ - [list langSelect refLangSelect readBtn writeBtn treeviewFrame origTextLabel origTextField translatedTextLabel translatedTextField refTextLabel refTextField] \ - [list langValue refLangValue origTextValue translatedTextValue refTextValue] -set gTrTreeview "$gTrTreeviewFrame.main" -set gTrTreeviewScrollbar "$gTrTreeviewFrame.scrollbar" - -grid rowconfigure $gTrFrame 0 -weight 1 -grid columnconfigure $gTrFrame 2 -weight 1 - -ttk::frame $gTrTreeviewFrame -borderwidth 1 -relief sunken -grid $gTrTreeviewFrame -column 0 -row 0 -columnspan 3 -sticky nsew -grid rowconfigure $gTrTreeviewFrame 0 -weight 1 -grid columnconfigure $gTrTreeviewFrame 0 -weight 1 -ttk::treeview $gTrTreeview -selectmode browse -columns {translation} -yscrollcommand {$gTrTreeviewScrollbar set} -grid $gTrTreeview -column 0 -row 0 -sticky nsew -bind $gTrTreeview <<TreeviewSelect>> gTrTreeviewSelectionCallback -ttk::scrollbar $gTrTreeviewScrollbar -orient vertical -command {$gTrTreeview yview} -grid $gTrTreeviewScrollbar -column 1 -row 0 -sticky ns -$gTrTreeview heading #0 -text "Original text" - -lmap i [list \ - [list \ - [ttk::label $gTrOrigTextLabel -text "Original" -anchor w] \ - {} \ - [ttk::entry $gTrOrigTextField -state readonly -textvariable gTrOrigTextValue] \ - ] \ - [list \ - [ttk::label $gTrTranslatedTextLabel -text "Translation" -anchor w] \ - [ttk::combobox $gTrLangSelect -exportselection false -state readonly -textvariable gTrLangValue] \ - [ttk::entry $gTrTranslatedTextField -textvariable gTrTranslatedTextValue] \ - ] \ - [list \ - [ttk::label $gTrRefTextLabel -text "Reference" -anchor w] \ - [ttk::combobox $gTrRefLangSelect -exportselection false -state readonly -textvariable gTrRefLangValue] \ - [ttk::entry $gTrRefTextField -state readonly -textvariable gTrRefTextValue] \ - ] \ -] row [list 1 2 3] { - lmap item $i col [list 0 1 2] { - if {$item eq ""} { - continue - } - grid $item -column $col -row $row -sticky nswe - } - grid rowconfigure $gTrFrame $row -uniform bottom - incr gTrRowCount -} - -bind $gTrLangSelect <<ComboboxSelected>> gTrLoadTranslationsToTreeview -trace add variable gTrTranslatedTextValue write gTrApplyTranslationString -bind $gTrRefLangSelect <<ComboboxSelected>> gTrTreeviewSelectionCallback - -proc gTrLoadTranslationsToTreeview {} { - global translationTemplate gTrTreeview gTrLangValue - $gTrTreeview heading translation -text "Translation: $gTrLangValue" - set prevFocus [$gTrTreeview item [$gTrTreeview focus] -text] - array set openedSections [list] - foreach i [$gTrTreeview children {}] { - if {[$gTrTreeview item $i -open]} { - set openedSections([$gTrTreeview item $i -text]) 1 - } - } - $gTrTreeview delete [$gTrTreeview children {}] - set parent {} - foreach i [lrange $translationTemplate 1 end] { - if {[regexp {^\#+\s*(.+)} $i x comment]} { - set parent [$gTrTreeview insert {} end -text $comment -tags {notranslate}] - if {[info exists openedSections($comment)]} { - $gTrTreeview item $parent -open true - } - if {$comment eq $prevFocus} { - $gTrTreeview focus $parent - $gTrTreeview selection set $parent - } - } elseif {$i ne ""} { - set last [$gTrTreeview insert $parent end -text $i -values [list [maybeGetTranslationString $gTrLangValue $i]]] - if {$i eq $prevFocus} { - $gTrTreeview focus $last - $gTrTreeview selection set $last - } - } - } - gTrTreeviewSelectionCallback -} - -proc gTrTreeviewSelectionCallback {} { - global gTrOrigTextValue gTrTreeview gTrLangSelect gTrLangValue gTrRefLangSelect gTrRefLangValue gTrTranslatedTextField gTrTranslatedTextValue gTrRefTextField gTrRefTextValue - set focused [$gTrTreeview focus] - set gTrOrigTextValue [$gTrTreeview item $focused -text] - if {$focused eq ""} { - $gTrTranslatedTextField state disabled - $gTrRefTextField state disabled - set gTrTranslatedTextValue "Select an entry to translate" - set gTrRefTextValue "" - } elseif {[$gTrTreeview tag has notranslate $focused]} { - $gTrTranslatedTextField state disabled - $gTrRefTextField state disabled - set gTrTranslatedTextValue "Category names cannot be translated" - set gTrRefTextValue "" - } else { - $gTrTranslatedTextField state !disabled - set gTrTranslatedTextValue [maybeGetTranslationString $gTrLangValue $gTrOrigTextValue] - set gTrRefTextValue [maybeGetTranslationString $gTrRefLangValue $gTrOrigTextValue] - if {$gTrRefLangValue eq ""} { - $gTrRefTextField state disabled - set gTrRefTextValue "" - } elseif {$gTrRefTextValue eq ""} { - $gTrRefTextField state disabled - set gTrRefTextValue "The selected string is not yet translated to the reference language" - } else { - $gTrRefTextField state !disabled - } - } - $gTrLangSelect selection clear - $gTrRefLangSelect selection clear -} - -proc gTrLoadTranslations {} { - global translationLangs gTrLangSelect gTrLangValue gTrRefLangSelect gTrRefLangValue - set prevLang $gTrLangValue - set prevRefLang $gTrRefLangValue - $gTrLangSelect configure -values $translationLangs - $gTrRefLangSelect configure -values [linsert $translationLangs 0 ""] - if {[llength $translationLangs] < 1} { - tk_messageBox -icon error type ok -title "Error" -message "No translation files present." - exit 1 - } - if {$prevLang ni $translationLangs} { - $gTrLangSelect current 0 - } - if {$prevRefLang ni $translationLangs} { - $gTrRefLangSelect current 0 - } - gTrLoadTranslationsToTreeview -} - -proc gTrApplyTranslationString args { - global gTrTreeview gTrLangValue gTrOrigTextValue gTrTranslatedTextValue - set focused [$gTrTreeview focus] - if {![$gTrTreeview tag has notranslate $focused]} { - setTranslationString $gTrLangValue $gTrOrigTextValue $gTrTranslatedTextValue - $gTrTreeview item $focused -values [list $gTrTranslatedTextValue] - } -} - -# Translation Template Editor - -gAddTab tm "Template" \ - [list addStringMenuBtn addHeadingMenuBtn removeMenuBtn moveMenuBtn textField setMenuBtn treeviewFrame] \ - [list textValue] -set gTmTreeview "$gTmTreeviewFrame.main" -set gTmTreeviewScrollbar "$gTmTreeviewFrame.scrollbar" - -set gTmRowCount 0 -foreach i [list \ - [gAddMenu gTmAddStringMenu [ttk::menubutton $gTmAddStringMenuBtn -text "Add string"] "menu" [list \ - [list command -label "Insert before current entry" -command {gTmInsertStringAt true 0}] \ - [list command -label "Insert after current entry" -command {gTmInsertStringAt true 1}] \ - [list command -label "Insert as the first entry" -command {gTmInsertStringAt false 0}] \ - [list command -label "Insert as the last entry" -command {gTmInsertStringAt false end}] \ - ]] \ - [gAddMenu gTmAddHeadingMenu [ttk::menubutton $gTmAddHeadingMenuBtn -text "Add heading"] "menu" [list \ - [list command -label "Insert before current section" -command {gTmInsertHeadingAt true 0}] \ - [list command -label "Insert after current section" -command {gTmInsertHeadingAt true 1}] \ - ]] \ - [gAddMenu gTmRemoveMenu [ttk::menubutton $gTmRemoveMenuBtn -text "Remove"] "menu" [list \ - [list command -label "Remove entry" -command gTmDeleteEntry] \ - [list command -label "Remove section" -command gTmDeleteEntry] \ - [list command -label "Merge with previous section" -command gTmMergeWithPrevious] \ - ]] \ - [gAddMenu gTmMoveMenu [ttk::menubutton $gTmMoveMenuBtn -text "Move"] "menu" [list \ - [list command -label "Up" -command {gTmMoveInSection true -1}] \ - [list command -label "Down" -command {gTmMoveInSection true 1}] \ - [list command -label "To first" -command {gTmMoveInSection false 0}] \ - [list command -label "To last" -command {gTmMoveInSection false end}] \ - ]] \ -] { - grid $i -column 1 -row $gTmRowCount -sticky we - incr gTmRowCount -} - -ttk::frame $gTmTreeviewFrame -borderwidth 1 -relief sunken -grid $gTmTreeviewFrame -column 0 -row 0 -rowspan [expr {1+$gTmRowCount}] -sticky nsew -grid rowconfigure $gTmTreeviewFrame 0 -weight 1 -grid columnconfigure $gTmTreeviewFrame 0 -weight 1 -grid rowconfigure $gTmFrame $gTmRowCount -weight 1 -grid columnconfigure $gTmFrame 0 -weight 1 -ttk::treeview $gTmTreeview -selectmode browse -show tree -yscrollcommand {$gTmTreeviewScrollbar set} -bind $gTmTreeview <<TreeviewSelect>> gTmTreeviewSelectionCallback -grid $gTmTreeview -column 0 -row 0 -sticky nsew -ttk::scrollbar $gTmTreeviewScrollbar -orient vertical -command {$gTmTreeview yview} -grid $gTmTreeviewScrollbar -column 1 -row 0 -sticky ns -incr gTmRowCount - -ttk::entry $gTmTextField -textvariable gTmTextValue -grid $gTmTextField -column 0 -row $gTmRowCount -sticky nsew - -gAddMenu gTmSetMenu [ttk::menubutton $gTmSetMenuBtn -text "Set"] "menu" [list \ - [list command -label "Set heading" -command gTmSetEntry] \ - [list command -label "Set and copy translations" -command gTmSetEntryAndCopy] \ - [list command -label "Set without copying translations" -command gTmSetEntry] \ -] -grid $gTmSetMenuBtn -column 1 -row $gTmRowCount -sticky nsew - -proc gTmLoadTranslationsToTreeview {} { - global translationTemplate gTmTreeview - set prevFocus [$gTmTreeview item [$gTmTreeview focus] -text] - array set openedSections [list] - foreach i [$gTmTreeview children {}] { - if {[$gTmTreeview item $i -open]} { - set openedSections([$gTmTreeview item $i -text]) 1 - } - } - $gTmTreeview delete [$gTmTreeview children {}] - set parent {} - foreach i [lrange $translationTemplate 1 end] { - if {[regexp {^\#+\s*(.+)} $i x comment]} { - set parent [$gTmTreeview insert {} end -text $comment -tags {heading}] - if {[info exists openedSections($comment)]} { - $gTmTreeview item $parent -open true - } - if {$comment eq $prevFocus} { - $gTmTreeview focus $parent - $gTmTreeview selection set $parent - } - } elseif {$i ne ""} { - set last [$gTmTreeview insert $parent end -text $i] - if {$i eq $prevFocus} { - $gTmTreeview focus $last - $gTmTreeview selection set $last - } - } - } - gTmTreeviewSelectionCallback -} - -proc gTmTreeviewSelectionCallback {} { - global gTmTreeview gTmTextField gTmTextValue gTmAddStringMenu gTmAddHeadingMenu gTmRemoveMenu gTmMoveMenu gTmSetMenu - set focused [$gTmTreeview focus] - if {$focused eq {}} { - $gTmTextField state disabled - set gTmTextValue "Select an entry to edit" - foreach m [list $gTmAddStringMenu $gTmAddHeadingMenu $gTmRemoveMenu $gTmMoveMenu $gTmSetMenu] { - for {set i 0} {$i <= [$m index end]} {incr i} { $m entryconfigure $i -state disabled} - } - } else { - $gTmTextField state !disabled - set headingSetState disabled - set entrySetState normal - if {[$gTmTreeview tag has heading $focused]} { - set headingSetState normal - set entrySetState disabled - } - foreach ent [list \ - [list $gTmAddStringMenu \ - [list 0 -state $entrySetState] \ - [list 1 -state $entrySetState] \ - [list 2 -state normal] \ - [list 3 -state normal] \ - ] \ - [list $gTmAddHeadingMenu \ - [list 0 -state normal] \ - [list 1 -state normal] \ - ] \ - [list $gTmMoveMenu \ - [list 0 -state normal] \ - [list 1 -state normal] \ - [list 2 -state normal] \ - [list 3 -state normal] \ - ] \ - [list $gTmRemoveMenu \ - [list 0 -state $entrySetState] \ - [list 1 -state $headingSetState] \ - [list 2 -state $headingSetState] \ - ] \ - [list $gTmSetMenu \ - [list 0 -state $headingSetState] \ - [list 1 -state $entrySetState] \ - [list 2 -state $entrySetState] \ - ] \ - ] { - set m [lindex $ent 0] - lmap i [lrange $ent 1 end] { - $m entryconfigure {*}$i - } - } - set gTmTextValue [$gTmTreeview item $focused -text] - } -} - -proc gTmUpdateTemplateAux {parent} { - global translationTemplate gTmTreeview - foreach i [$gTmTreeview children $parent] { - set tval [$gTmTreeview item $i -text] - if {[$gTmTreeview tag has heading $i]} { - lappend translationTemplate {} - set tval "# $tval" - } - lappend translationTemplate $tval - gTmUpdateTemplateAux $i - } -} - -proc gTmUpdateTemplate {} { - global translationTemplate translationDomain - set translationTemplate [list "# textdomain: $translationDomain"] - gTmUpdateTemplateAux {} - gTrLoadTranslations - gTmLoadTranslationsToTreeview -} - -proc gTmSetEntry {} { - global gTmTreeview gTmTextValue - $gTmTreeview item [$gTmTreeview focus] -text $gTmTextValue - gTmUpdateTemplate -} - -proc gTmSetEntryAndCopy {} { - global gTmTreeview gTmTextValue - set focus [$gTmTreeview focus] - rewordTranslationString [$gTmTreeview item $focus -text] $gTmTextValue - gTmSetEntry -} - -proc gTmInsertStringAt {relative idx} { - global gTmTreeview - set focus [$gTmTreeview focus] - set parent [$gTmTreeview parent $focus] - set relidx [$gTmTreeview index $focus] - if {[$gTmTreeview tag has heading $focus]} { - set parent $focus - set relindex 0 - } - set newidx $idx - if {$relative} { - set newidx [expr {$idx+$relidx}] - } - set item [$gTmTreeview insert $parent $newidx -text {}] - $gTmTreeview focus $item - $gTmTreeview selection set $item -} - -proc gTmInsertHeadingAt {relative idx} { - global gTmTreeview - set focus [$gTmTreeview focus] - if {![$gTmTreeview tag has heading $focus]} { - set focus [$gTmTreeview parent $focus] - } - set parent [$gTmTreeview parent $focus] - set relidx [$gTmTreeview index $focus] - if {$focus eq {}} { - set parent {} - set relidx 0 - } - set newidx $idx - if {$relative} { - set newidx [expr {$idx+$relidx}] - } - set item [$gTmTreeview insert $parent $newidx -text {} -tags {heading}] - $gTmTreeview focus $item - $gTmTreeview selection set $item -} - -proc gTmMoveInSection {relative idx} { - global gTmTreeview - set focus [$gTmTreeview focus] - set parent [$gTmTreeview parent $focus] - set relidx [$gTmTreeview index $focus] - set newidx $idx - if {$relative} { - set newidx [expr {$idx+$relidx}] - } - $gTmTreeview move $focus $parent $newidx - gTmUpdateTemplate -} - -proc gTmDeleteEntry {} { - global gTmTreeview - $gTmTreeview delete [$gTmTreeview focus] - gTmUpdateTemplate -} - -proc gTmMergeWithPrevious {} { - global gTmTreeview - set parent [$gTmTreeview focus] - set prev [$gTmTreeview prev $parent] - set newindex end - if {$prev eq {}} { - set prev [$gTmTreeview parent $parent] - set newindex 0 - } - foreach i [$gTmTreeview children $parent] { - $gTmTreeview move $i $prev $newindex - } - $gTmTreeview delete $parent - gTmUpdateTemplate -} - -proc gTmLoadTranslations {} { - gTmLoadTranslationsToTreeview -} - -# Initialization - -gReloadTranslations diff --git a/advtrains/locale/template.txt b/advtrains/locale/template.txt deleted file mode 100644 index 8c8b859..0000000 --- a/advtrains/locale/template.txt +++ /dev/null @@ -1,146 +0,0 @@ -# textdomain: advtrains - -# Advtrains Core (unorganized) -This wagon is owned by @1, you can't destroy it.=This wagon is owned by @1, you can't destroy it. -Warning: If you destroy this wagon, you only get some steel back! If you are sure, hold Sneak and left-click the wagon.=Warning: If you destroy this wagon, you only get some steel back! If you are sure, hold Sneak and left-click the wagon. -This position is protected!=This position is protected! -Can't place: not pointing at node=Can't place: not pointing at node -Can't place: space occupied!=Can't place: space occupied! -Can't place: protected position!=Can't place: protected position! -Can't place: Not enough slope items left (@1 required)=Can't place: Not enough slope items left (@1 required) -Can't place: There's no slope of length @1=Can't place: There's no slope of length @1 -Can't place: no supporting node at upper end.=Can't place: no supporting node at upper end. -Deprecated Track=Deprecated Track -Can't get on: wagon full or doors closed!=Can't get on: wagon full or doors closed! -Use Sneak+rightclick to bypass closed doors!=Use Sneak+rightclick to bypass closed doors! -Doors are closed! Use Sneak+rightclick to ignore the closed doors and get off!=Doors are closed! Use Sneak+rightclick to ignore the closed doors and get off! -Access to @1=Access to @1 -You do not have the @1 privilege.=You do not have the @1 privilege. -The wagon's inventory is not empty!=The wagon's inventory is not empty! -Position is occupied by a train.=Position is occupied by a train. -There's a Track Circuit Break here.=There's a Track Circuit Break here. -There's a Signal Influence Point here.=There's a Signal Influence Point here. - -# Trackworker, rotation, adjustment -This node can't be rotated using the trackworker!=This node can't be rotated using the trackworker! -This node can't be changed using the trackworker!=This node can't be changed using the trackworker! -This track can not be changed!=This track can not be changed! -This track can not be rotated!=This track can not be rotated! -This track can not be removed!=This track can not be removed! - -# ATC -ATC controller, unconfigured.=ATC controller, unconfigured. -ATC controller=ATC controller -ATC controller, mode @1@nChannel: @2=ATC controller, mode @1@nChannel: @2 -ATC controller, mode @1@nCommand: @2=ATC controller, mode @1@nCommand: @2 -Command=Command -Command (on)=Command (on) -Digiline channel=Digiline channel -ATC Kick command warning: Doors closed=ATC Kick command warning: Doors closed -ATC Kick command warning: Train moving=ATC Kick command warning: Train moving -ATC Reverse command warning: didn't reverse train, train moving!=ATC Reverse command warning: didn't reverse train, train moving! -ATC command syntax error: I statement not closed: @1=ATC command syntax error: I statement not closed: @1 -ATC command parse error: Unknown command: @1=ATC command parse error: Unknown command: @1 - -# Coupling -Lock couples=Lock couples -You need to own at least one neighboring wagon to destroy this couple.=You need to own at least one neighboring wagon to destroy this couple. -Buffer and Chain Coupler=Buffer and Chain Coupler -Scharfenberg Coupler=Scharfenberg Coupler -Japanese Train Inter-Wagon Connection=Japanese Train Inter-Wagon Connection -Can not couple: The couplers of the trains do not match (@1 and @2).=Can not couple: The couplers of the trains do not match (@1 and @2). -You are not allowed to couple trains without the train_operator privilege.=You are not allowed to couple trains without the train_operator privilege. - -# Clipboard -The track you are trying to place the wagon on is not long enough!=The track you are trying to place the wagon on is not long enough! -The clipboard couldn't access the metadata. Paste failed.=The clipboard couldn't access the metadata. Paste failed. -The clipboard couldn't access the metadata. Copy failed.=The clipboard couldn't access the metadata. Copy failed. -The clipboard is empty.=The clipboard is empty. -Back of train would end up off track, cancelling.=Back of train would end up off track, cancelling. -No such lua entity!=No such lua entity! -No such wagon: @1=No such wagon: @1 -No such train: @1=No such train: @1 -Train copied!=Train copied! - -# Protection -You are not allowed to build tracks without the track_builder privilege.=You are not allowed to build tracks without the track_builder privilege. -You are not allowed to build near tracks without the track_builder privilege.=You are not allowed to build near tracks without the track_builder privilege. -You are not allowed to build tracks at this protected position.=You are not allowed to build tracks at this protected position. -You are not allowed to build near tracks at this protected position.=You are not allowed to build near tracks at this protected position. -You are not allowed to operate turnouts and signals without the railway_operator privilege.=You are not allowed to operate turnouts and signals without the railway_operator privilege. - -# Train HUD/Formspecs -Speed:=Speed: -Target:=Target: -Show Inventory=Show Inventory -Select seat:=Select seat: -Wagon properties=Wagon properties -Save wagon properties=Save wagon properties -Text displayed outside on train=Text displayed outside on train -Text displayed inside train=Text displayed inside train -Line=Line -Routingcode=Routingcode -Get off=Get off -Get off (forced)=Get off (forced) -(Doors closed)=(Doors closed) - -# General -Save=Save - -# Line automation -Station Code=Station Code -Station Name=Station Name -Door Delay=Door Delay -Door Side=Door Side -Dep. Speed=Dep. Speed -Stop Time=Stop Time - -# Items -Track Worker Tool@n@nLeft-click: change rail type (straight/curve/switch)@nRight-click: rotate rail/bumper/signal/etc.=Track Worker Tool@n@nLeft-click: change rail type (straight/curve/switch)@nRight-click: rotate rail/bumper/signal/etc. -Passive Component Naming Tool@n@nRight-click to name a passive component.=Passive Component Naming Tool@n@nRight-click to name a passive component. -Train copy/paste tool@n@nLeft-click: copy train@nRight-click: paste train=Train copy/paste tool@n@nLeft-click: copy train@nRight-click: paste train -Track=Track -Perpendicular Diamond Crossing Track=Perpendicular Diamond Crossing Track -Diagonal Diamond Crossing Track=Diagonal Diamond Crossing Track -90+Angle Diamond Crossing Track=90+Angle Diamond Crossing Track -Y-turnout=Y-turnout -3-way turnout=3-way turnout -Unloading Track=Unloading Track -Loading Track=Loading Track -Bumper=Bumper -Detector Rail=Detector Rail -@1 Slope=@1 Slope -@1 Platform (low)=@1 Platform (low) -@1 Platform (high)=@1 Platform (high) -@1 Platform (low, 45 degree)=@1 Platform (low, 45 degree) -@1 Platform (45 degree)=@1 Platform (45 degree) -Lampless Signal=Lampless Signal -Signal=Signal -Wallmounted Signal (l)=Wallmounted Signal (l) -Wallmounted Signal (r)=Wallmounted Signal (r) -Wallmounted Signal (t)=Wallmounted Signal (t) -Andrew's Cross=Andrew's Cross -Boiler=Boiler -driver's cab=driver's cab -Wheel=Wheel -Chimney=Chimney - -# Seats -Default Seat=Default Seat -Default Seat (driver stand)=Default Seat (driver stand) -Driver stand=Driver stand -Driver Stand (left)=Driver Stand (left) -Driver Stand (right)=Driver Stand (right) - -# Wagon/engine types -Industrial Train Engine=Industrial Train Engine -Big Industrial Train Engine=Big Industrial Train Engine -Industrial tank wagon=Industrial tank wagon -Industrial wood wagon=Industrial wood wagon -Japanese Train Engine=Japanese Train Engine -Japanese Train Wagon=Japanese Train Wagon -Steam Engine=Steam Engine -Detailed Steam Engine=Detailed Steam Engine -Passenger Wagon=Passenger Wagon -Box Wagon=Box Wagon -Subway Passenger Wagon=Subway Passenger Wagon diff --git a/advtrains/locale/topo.sh b/advtrains/locale/topo.sh deleted file mode 100755 index 23f81b1..0000000 --- a/advtrains/locale/topo.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -head -n18 ../po/template.pot | sed 's/charset=CHARSET/charset=UTF-8/' -sed -En 's/@n/\\n/g;s/@\n/\\n/g;s/\"/\\"/g;s/^([^=]+)=\1$/\1=/;s/^([^=]+)=([^=]*)$/\nmsgid "\1"\nmsgstr "\2"/gp' diff --git a/advtrains/po/README.md b/advtrains/po/README.md new file mode 100644 index 0000000..3e94682 --- /dev/null +++ b/advtrains/po/README.md @@ -0,0 +1,70 @@ +# Translations +Please read this document before working on any translations. + +Unlike many other mods, Advtrains uses `.po` files for localization, +which are then automatically converted to `.tr` files when the mod is +loaded. Therefore, please submit patches that edit the `.po` files. + +## Getting Started +The translation files can be edited like any other `.po` file. + +If the translation file for your language does not exist, create it by +copying `template.txt` to `advtrains.XX.tr`, where `XX` is replaced by +the language code. + +Feel free to use the [discussion mailing list][srht-discuss] if you +have any questions regarding localization. + +You can share your `.po` file directly or [as a patch][gsm] to the [dev +mailing list][srht-devel]. The latter is encouraged, but, unlike code +changes, translation files sent directly are also accepted. + +[tr-format]: https://minetest.gitlab.io/minetest/translations/#translation-file-format +[srht-discuss]: https://lists.sr.ht/~gpcf/advtrains-discuss +[srht-devel]: https://lists.sr.ht/~gpcf/advtrains-devel +[gsm]: https://git-send-email.io + +## Translation Notes +* Translations should be consistent. You can use other entries or the +translations in Minetest as a reference. +* Translations do not have to fully correspond to the original text - +they only need to provide the same information. In particular, +translations do not need to have the same linguistical structure as the +original text. +* Replacement sequences (`@1`, `@2`, etc) should not be translated. +* Certain abbreviations or names, such as "Ks" or "Zs 3", should +generally not be translated. + +### (de) German +* Verwenden Sie die neue Rechtschreibung und die Sie-Form. +* Mit der deutschen Tastaturbelegung unter Linux können die +Anführungszeichen „“ mit AltGr-V bzw. AltGr-B eingegeben werden. + +### (zh) Chinese +(This section is written in English to avoid writing the note twice or +using only one of the variants, as most of this section applies to both +the traditional and simplified variants.) + +* Please use the 「」 quotation marks for Traditional Chinese and “” +for Simplified Chinese. +* Please use the fullwidth variants of: , 、 。 ? ! : ; +* Please use the halfwidth variants of: ( ) [ ] / \ | +* Please do not leave any space between Han characters (including +fullwidth punctuation marks). +* Please leave a space between Han characters (excluding fullwidth +punctuation marks) and characters from other scripts (including +halfwidth punctuation marks). However, do not leave any space between +Han characters and Arabic numerals. + +## Notes for developers +* The `update-translations.sh` script can be used to update the +translation files. However, please make sure to install the +`basic_trains` mod before running the script. +* Please make sure that the first argument to `S` (or `attrans`) _only_ +includes string literals without formatting or concatenation. This is +unfortunately a limitation of the `xgettext` utility. +* Avoid word-by-word translations. +* Avoid manipulating translated strings (except for concatenation). Use +server-side translations if you have to modify the text sent to users. +* Avoid truncating strings unless multibyte characters are handled +properly. diff --git a/advtrains/poconvert.lua b/advtrains/poconvert.lua new file mode 100644 index 0000000..c7704f6 --- /dev/null +++ b/advtrains/poconvert.lua @@ -0,0 +1,159 @@ +local unescape_string +do + local schartbl = { -- https://en.wikipedia.org/wiki/Escape_sequences_in_C + a = "\a", + b = "\b", + e = string.char(0x1b), + f = "\f", + n = "\n", + r = "\r", + t = "\t", + v = "\v", + } + local function replace_single(pfx, c) + local pl = #pfx + if pl % 2 == 0 then + return pfx .. c + end + return string.sub(pfx, 1, math.floor(pl/2)) .. (schartbl[c] or c) + end + unescape_string = function(str) + return (string.gsub(str, [[(\+)([abefnrtv'"?])]], replace_single):gsub([[\\]], [[\]])) + end +end + +local function readstring_aux(str, pos) + local _, spos = string.find(str, [[^%s*"]], pos) + if not spos then + return nil + end + local ipos = spos + while true do + local _, epos, m = string.find(str, [[(\*)"]], ipos+1) + if not epos then + return error("String extends beyond the end of input") + end + ipos = epos + if #m % 2 == 0 then + return unescape_string(string.sub(str, spos+1, epos-1)), epos+1 + end + end +end + +local function readstring(str, pos) + local st = {} + local nxt = pos + while true do + local s, npos = readstring_aux(str, nxt) + if not s then + if not st[1] then + return nil, nxt + else + return table.concat(st), nxt + end + end + nxt = npos + table.insert(st, s) + end +end + +local function readtoken(str, pos) + local _, epos, tok = string.find(str, [[^%s*(%S+)]], pos) + if not epos then + return nil, pos + end + return tok, epos+1 +end + +local function readcomment_aux(str, pos) + local _, epos, sval = string.find(str, "^\n*#%s*([^\n]*)", pos) + if not epos then + return nil + end + return sval, epos+1 +end + +local function readcomment(str, pos) + local st = {} + local nxt = pos + while true do + local s, npos = readcomment_aux(str, nxt) + if not npos then + return table.concat(st, "\n"), nxt + end + table.insert(st, s) + nxt = npos + end +end + +local function readpo(str) + local st = {} + local pos = 1 + while true do + local tok + local _, npos = readcomment(str, pos) + tok, npos = readtoken(str, npos) + if not tok then + return st + end + assert(tok == "msgid", "Invalid token: " .. tok) + local orig, tr + orig, npos = readstring(str, npos) + assert(orig ~= nil, "Missing untranslated string") + tok, npos = readtoken(str, npos) + assert(tok == "msgstr", "Invalid token: " .. tok) + tr, npos = readstring(str, npos) + assert(tr ~= nil, "Missing translated string") + if not (orig == "" or tr == "") then + st[orig] = tr + end + pos = npos + end +end + +local escape_lookup = { + ["="] = "@=", + ["\n"] = "@n" +} +local function escape_string(st) + return (string.gsub(st, "[=\n]", escape_lookup)) +end + +local function convert_po_string(textdomain, str) + local st = {string.format("# textdomain: %s", textdomain)} + for k, v in pairs(readpo(str)) do + table.insert(st, ("%s=%s"):format(escape_string(k), escape_string(v))) + end + return table.concat(st, "\n") +end + +local function convert_po_file(textdomain, inpath, outpath) + local f, err = io.open(inpath, "rb") + assert(f, err) + local str = convert_po_string(textdomain, f:read("*a")) + f:close() + minetest.safe_file_write(outpath, str) + return str +end + +local function convert_flat_po_directory(textdomain, modpath) + assert(textdomain, "No textdomain specified for po file conversion") + local mp = modpath or minetest.get_modpath(textdomain) + assert(mp ~= nil, "No path to write for " .. textdomain) + local popath = mp .. "/po" + local trpath = mp .. "/locale" + for _, infile in pairs(minetest.get_dir_list(popath, false)) do + local lang = string.match(infile, [[^([^%.]+)%.po$]]) + if lang then + local inpath = popath .. "/" .. infile + local outpath = ("%s/%s.%s.tr"):format(trpath, textdomain, lang) + convert_po_file(textdomain, inpath, outpath) + end + end +end + +return { + from_string = convert_po_string, + from_file = convert_po_file, + from_flat = convert_flat_po_directory, +} |