Add TypeScript support.

* autopull.sh: Check out tree-sitter-typescript. Set
TREE_SITTER_TYPESCRIPT_VERSION.
* gettext-tools/build-aux/tree-sitter-typescript-portability.diff: New file.
* gettext-tools/configure.ac: Set TREE_SITTER_TYPESCRIPT_VERSION.
* gettext-tools/Makefile.am (EXTRA_DIST): Add the tree-sitter-typescript source
code and patch.
* gettext-tools/doc/lang-typescript.texi: New file.
* gettext-tools/doc/Makefile.am (gettext_TEXINFOS): Add it.
* gettext-tools/doc/gettext.texi (No string concatenation): Mention string
concatenation in TypeScript.
(List of Programming Languages): Include lang-typescript.texi.
* gettext-tools/doc/xgettext.texi: Document the -L TypeScript and -L TSX
options.
* gettext-tools/src/x-typescript-impl.h: New file.
* gettext-tools/src/x-typescript.h: New file.
* gettext-tools/src/x-typescript.c: New file.
* gettext-tools/src/x-typescriptx.h: New file.
* gettext-tools/src/x-typescriptx.c: New file.
* gettext-tools/src/xgettext.c: Include x-typescript.h, x-typescriptx.h.
(flag_table_typescript, flag_table_typescriptx): New variables.
(main): Invoke init_flag_table_typescript, init_flag_table_typescriptx,
x_typescript_extract_all, x_typescriptx_extract_all, x_typescript_keyword,
x_typescriptx_keyword.
(usage): Document the -L TypeScript and -L TSX options.
(xgettext_record_flag): Support format_javascript with TypeScript and TSX.
(language_to_extractor, extension_to_language): Support TypeScript and TSX.
* gettext-tools/src/FILES: Mention x-typescript.h, x-typescript.c,
x-typescriptx.h, x-typescriptx.c, x-typescript-impl.h.
* gettext-tools/src/Makefile.am (noinst_LIBRARIES): Reference LIBXGETTEXTTS.
(noinst_HEADERS): Add x-typescript.h, x-typescriptx.h, x-typescript-impl.h.
(LIBXGETTEXTTS): Add libxgettextts3.a, libxgettextts4.a.
(libxgettextts3_a_SOURCES, libxgettextts3_a_CPPFLAGS): New variables.
(libxgettextts4_a_SOURCES, libxgettextts4_a_CPPFLAGS): New variables.
(xgettext_SOURCES): Add x-typescript.c, x-typescriptx.c.
* gettext-tools/tests/xgettext-javascript-6: Improve comments.
* gettext-tools/tests/xgettext-typescript-1: New file, based on
gettext-tools/tests/xgettext-javascript-1.
* gettext-tools/tests/xgettext-typescript-2: New file, based on
gettext-tools/tests/xgettext-javascript-2.
* gettext-tools/tests/xgettext-typescript-3: New file, based on
gettext-tools/tests/xgettext-javascript-3.
* gettext-tools/tests/xgettext-typescript-4: New file, based on
gettext-tools/tests/xgettext-javascript-4.
* gettext-tools/tests/xgettext-typescript-5: New file, based on
gettext-tools/tests/xgettext-javascript-5.
* gettext-tools/tests/xgettext-typescript-6: New file, based on
gettext-tools/tests/xgettext-javascript-6.
* gettext-tools/tests/xgettext-typescript-7: New file, based on
gettext-tools/tests/xgettext-javascript-7.
* gettext-tools/tests/Makefile.am (TESTS): Add the new tests.
* NEWS: Mention the TypeScript support.
This commit is contained in:
Bruno Haible 2025-03-11 09:55:56 +01:00
parent 365f43a759
commit 4fa2cffa94
27 changed files with 2077 additions and 23 deletions

2
.gitignore vendored
View File

@ -954,6 +954,8 @@ core
/gettext-tools/src/gettext.res
/gettext-tools/src/libxgettextts1.a
/gettext-tools/src/libxgettextts2.a
/gettext-tools/src/libxgettextts3.a
/gettext-tools/src/libxgettextts4.a
/gettext-tools/src/textstyle.h
/gettext-tools/src/textstyle/stdbool.h
/gettext-tools/src/textstyle/version.h

3
NEWS
View File

@ -6,6 +6,9 @@ Version 0.25 - March 2025
- 'msgfmt -c' now verifies the syntax of translations of Go format
strings.
- New examples 'hello-go' and 'hello-go-http' have been added.
* TypeScript:
- xgettext now supports TypeScript and TSX (= TypeScript with JSX
extensions).
Version 0.24 - February 2025

View File

@ -88,6 +88,7 @@ func_git_clone_shallow ()
TREE_SITTER_VERSION=0.23.2
TREE_SITTER_GO_VERSION=0.23.4
TREE_SITTER_RUST_VERSION=0.23.2
TREE_SITTER_TYPESCRIPT_VERSION=0.23.2
# Cache the relevant source code. Erase the rest of the tree-sitter projects.
test -d gettext-tools/tree-sitter-$TREE_SITTER_VERSION || {
func_git_clone_shallow tree-sitter https://github.com/tree-sitter/tree-sitter.git v$TREE_SITTER_VERSION
@ -116,10 +117,28 @@ test -d gettext-tools/tree-sitter-rust-$TREE_SITTER_RUST_VERSION || {
mv gettext-tools/tree-sitter-rust-$TREE_SITTER_RUST_VERSION/src/scanner.c gettext-tools/tree-sitter-rust-$TREE_SITTER_RUST_VERSION/src/rust-scanner.c
rm -rf tree-sitter-rust
}
test -d gettext-tools/tree-sitter-typescript-$TREE_SITTER_TYPESCRIPT_VERSION || {
func_git_clone_shallow tree-sitter-typescript https://github.com/tree-sitter/tree-sitter-typescript.git v$TREE_SITTER_TYPESCRIPT_VERSION
(cd tree-sitter-typescript && patch -p1) < gettext-tools/build-aux/tree-sitter-typescript-portability.diff
mkdir gettext-tools/tree-sitter-typescript-$TREE_SITTER_TYPESCRIPT_VERSION
mkdir gettext-tools/tree-sitter-typescript-$TREE_SITTER_TYPESCRIPT_VERSION/common
mkdir gettext-tools/tree-sitter-typescript-$TREE_SITTER_TYPESCRIPT_VERSION/typescript
mkdir gettext-tools/tree-sitter-typescript-$TREE_SITTER_TYPESCRIPT_VERSION/tsx
mv tree-sitter-typescript/LICENSE gettext-tools/tree-sitter-typescript-$TREE_SITTER_TYPESCRIPT_VERSION/LICENSE
mv tree-sitter-typescript/common/scanner.h gettext-tools/tree-sitter-typescript-$TREE_SITTER_TYPESCRIPT_VERSION/common/scanner.h
mv tree-sitter-typescript/typescript/src gettext-tools/tree-sitter-typescript-$TREE_SITTER_TYPESCRIPT_VERSION/typescript/src
mv tree-sitter-typescript/tsx/src gettext-tools/tree-sitter-typescript-$TREE_SITTER_TYPESCRIPT_VERSION/tsx/src
mv gettext-tools/tree-sitter-typescript-$TREE_SITTER_TYPESCRIPT_VERSION/typescript/src/parser.c gettext-tools/tree-sitter-typescript-$TREE_SITTER_TYPESCRIPT_VERSION/typescript/src/ts-parser.c
mv gettext-tools/tree-sitter-typescript-$TREE_SITTER_TYPESCRIPT_VERSION/typescript/src/scanner.c gettext-tools/tree-sitter-typescript-$TREE_SITTER_TYPESCRIPT_VERSION/typescript/src/ts-scanner.c
mv gettext-tools/tree-sitter-typescript-$TREE_SITTER_TYPESCRIPT_VERSION/tsx/src/parser.c gettext-tools/tree-sitter-typescript-$TREE_SITTER_TYPESCRIPT_VERSION/tsx/src/tsx-parser.c
mv gettext-tools/tree-sitter-typescript-$TREE_SITTER_TYPESCRIPT_VERSION/tsx/src/scanner.c gettext-tools/tree-sitter-typescript-$TREE_SITTER_TYPESCRIPT_VERSION/tsx/src/tsx-scanner.c
rm -rf tree-sitter-typescript
}
cat > gettext-tools/tree-sitter.cfg <<EOF
TREE_SITTER_VERSION=$TREE_SITTER_VERSION
TREE_SITTER_GO_VERSION=$TREE_SITTER_GO_VERSION
TREE_SITTER_RUST_VERSION=$TREE_SITTER_RUST_VERSION
TREE_SITTER_TYPESCRIPT_VERSION=$TREE_SITTER_TYPESCRIPT_VERSION
EOF
dir0=`pwd`

View File

@ -86,8 +86,20 @@ EXTRA_DIST += \
tree-sitter-rust-$(TREE_SITTER_RUST_VERSION)/src/rust-scanner.c \
tree-sitter-rust-$(TREE_SITTER_RUST_VERSION)/src/tree_sitter/alloc.h \
tree-sitter-rust-$(TREE_SITTER_RUST_VERSION)/src/tree_sitter/array.h \
tree-sitter-rust-$(TREE_SITTER_RUST_VERSION)/src/tree_sitter/parser.h
tree-sitter-rust-$(TREE_SITTER_RUST_VERSION)/src/tree_sitter/parser.h \
build-aux/tree-sitter-typescript-portability.diff \
tree-sitter-typescript-$(TREE_SITTER_TYPESCRIPT_VERSION)/LICENSE \
tree-sitter-typescript-$(TREE_SITTER_TYPESCRIPT_VERSION)/common/scanner.h \
tree-sitter-typescript-$(TREE_SITTER_TYPESCRIPT_VERSION)/typescript/src/ts-parser.c \
tree-sitter-typescript-$(TREE_SITTER_TYPESCRIPT_VERSION)/typescript/src/ts-scanner.c \
tree-sitter-typescript-$(TREE_SITTER_TYPESCRIPT_VERSION)/typescript/src/tree_sitter/alloc.h \
tree-sitter-typescript-$(TREE_SITTER_TYPESCRIPT_VERSION)/typescript/src/tree_sitter/array.h \
tree-sitter-typescript-$(TREE_SITTER_TYPESCRIPT_VERSION)/typescript/src/tree_sitter/parser.h \
tree-sitter-typescript-$(TREE_SITTER_TYPESCRIPT_VERSION)/tsx/src/tsx-parser.c \
tree-sitter-typescript-$(TREE_SITTER_TYPESCRIPT_VERSION)/tsx/src/tsx-scanner.c \
tree-sitter-typescript-$(TREE_SITTER_TYPESCRIPT_VERSION)/tsx/src/tree_sitter/alloc.h \
tree-sitter-typescript-$(TREE_SITTER_TYPESCRIPT_VERSION)/tsx/src/tree_sitter/array.h \
tree-sitter-typescript-$(TREE_SITTER_TYPESCRIPT_VERSION)/tsx/src/tree_sitter/parser.h
# Files installed for the user.

View File

@ -0,0 +1,64 @@
diff --git a/tsx/src/parser.c b/tsx/src/parser.c
index faa8aa4..726e493 100644
--- a/tsx/src/parser.c
+++ b/tsx/src/parser.c
@@ -282905,8 +282905,10 @@ void tree_sitter_tsx_external_scanner_deserialize(void *, const char *, unsigned
#define TS_PUBLIC
#elif defined(_WIN32)
#define TS_PUBLIC __declspec(dllexport)
-#else
+#elif defined __GNUC__ || defined __clang__
#define TS_PUBLIC __attribute__((visibility("default")))
+#else
+#define TS_PUBLIC
#endif
TS_PUBLIC const TSLanguage *tree_sitter_tsx(void) {
diff --git a/tsx/src/tree_sitter/parser.h b/tsx/src/tree_sitter/parser.h
index 799f599..130b4d0 100644
--- a/tsx/src/tree_sitter/parser.h
+++ b/tsx/src/tree_sitter/parser.h
@@ -155,8 +155,10 @@ static inline bool set_contains(TSCharacterRange *ranges, uint32_t len, int32_t
#ifdef _MSC_VER
#define UNUSED __pragma(warning(suppress : 4101))
-#else
+#elif defined __GNUC__ || defined __clang__
#define UNUSED __attribute__((unused))
+#else
+#define UNUSED
#endif
#define START_LEXER() \
diff --git a/typescript/src/parser.c b/typescript/src/parser.c
index a88f8e1..b03339e 100644
--- a/typescript/src/parser.c
+++ b/typescript/src/parser.c
@@ -282387,8 +282387,10 @@ void tree_sitter_typescript_external_scanner_deserialize(void *, const char *, u
#define TS_PUBLIC
#elif defined(_WIN32)
#define TS_PUBLIC __declspec(dllexport)
-#else
+#elif defined __GNUC__ || defined __clang__
#define TS_PUBLIC __attribute__((visibility("default")))
+#else
+#define TS_PUBLIC
#endif
TS_PUBLIC const TSLanguage *tree_sitter_typescript(void) {
diff --git a/typescript/src/tree_sitter/parser.h b/typescript/src/tree_sitter/parser.h
index 799f599..130b4d0 100644
--- a/typescript/src/tree_sitter/parser.h
+++ b/typescript/src/tree_sitter/parser.h
@@ -155,8 +155,10 @@ static inline bool set_contains(TSCharacterRange *ranges, uint32_t len, int32_t
#ifdef _MSC_VER
#define UNUSED __pragma(warning(suppress : 4101))
-#else
+#elif defined __GNUC__ || defined __clang__
#define UNUSED __attribute__((unused))
+#else
+#define UNUSED
#endif
#define START_LEXER() \

View File

@ -574,6 +574,7 @@ dnl a newer version of tree-sitter-<lang>.
AC_SUBST([TREE_SITTER_VERSION])
AC_SUBST([TREE_SITTER_GO_VERSION])
AC_SUBST([TREE_SITTER_RUST_VERSION])
AC_SUBST([TREE_SITTER_TYPESCRIPT_VERSION])
PACKAGE_SUFFIX="-$ARCHIVE_VERSION"
AC_SUBST([PACKAGE_SUFFIX])

View File

@ -64,6 +64,7 @@ gettext_TEXINFOS = \
lang-java.texi \
lang-csharp.texi \
lang-javascript.texi \
lang-typescript.texi \
lang-scheme.texi \
lang-lisp.texi \
lang-clisp-c.texi \

View File

@ -432,6 +432,7 @@ Individual Programming Languages
* Java:: Java
* C#:: C#
* JavaScript:: JavaScript
* TypeScript:: TypeScript
* Scheme:: GNU guile - Scheme
* Common Lisp:: GNU clisp - Common Lisp
* clisp C:: GNU clisp C sources
@ -2323,6 +2324,7 @@ at runtime (or possibly at compile time, if the compiler supports that).
@cindex Java, string concatenation
@cindex C#, string concatenation
@cindex JavaScript, string concatenation
@cindex TypeScript, string concatenation
@cindex Go, string concatenation
@cindex Ruby, string concatenation
@cindex Shell, string concatenation
@ -2347,7 +2349,7 @@ In Java, string concatenation is denoted by the @samp{+} operator.
In C#, string concatenation is denoted by the @samp{+} operator.
@c Reference: https://learn.microsoft.com/en-us/dotnet/csharp/how-to/concatenate-multiple-strings
@item
In JavaScript, string concatenation is denoted by the @samp{+} operator.
In JavaScript and TypeScript, string concatenation is denoted by the @samp{+} operator.
@c Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Addition
@item
In Go, string concatenation is denoted by the @samp{+} operator.
@ -10426,6 +10428,7 @@ that language, and to combine the resulting files using @code{msgcat}.
* Java:: Java
* C#:: C#
* JavaScript:: JavaScript
* TypeScript:: TypeScript
* Scheme:: GNU guile - Scheme
* Common Lisp:: GNU clisp - Common Lisp
* clisp C:: GNU clisp C sources
@ -10455,6 +10458,7 @@ that language, and to combine the resulting files using @code{msgcat}.
@include lang-java.texi
@include lang-csharp.texi
@include lang-javascript.texi
@include lang-typescript.texi
@include lang-scheme.texi
@include lang-lisp.texi
@include lang-clisp-c.texi

View File

@ -0,0 +1,64 @@
@c This file is part of the GNU gettext manual.
@c Copyright (C) 1995-2025 Free Software Foundation, Inc.
@c See the file gettext.texi for copying conditions.
@node TypeScript
@subsection TypeScript and TSX
@table @asis
@item RPMs
js
@item Ubuntu packages
gjs
@item File extension
@code{ts} for TypeScript, @code{tsx} for TSX (TypeScript with JSX)
@item String syntax
@itemize @bullet
@item @code{"abc"}
@item @code{'abc'}
@item @code{`abc`}
@end itemize
@item gettext shorthand
@code{_("abc")}
@item gettext/ngettext functions
@code{gettext}, @code{dgettext}, @code{dcgettext}, @code{ngettext},
@code{dngettext}
@item textdomain
@code{textdomain} function
@item bindtextdomain
@code{bindtextdomain} function
@item setlocale
automatic
@item Prerequisite
unknown
@item Use or emulate GNU gettext
use, or emulate
@item Extractor
@code{xgettext}
@item Formatting with positions
A @code{format} method on strings can be used.
But since it is not standard in TypeScript,
you have to enable it yourself. @c TODO How?
@item Portability
On platforms without gettext, the functions are not available.
@item po-mode marking
---
@end table

View File

@ -79,6 +79,7 @@ Specifies the language of the input files. The supported languages are
@code{Java}, @code{JavaProperties},
@code{C#},
@code{JavaScript},
@code{TypeScript}, @code{TSX},
@code{Scheme}, @code{Guile},
@code{Lisp},
@code{EmacsLisp},
@ -314,6 +315,7 @@ Python,
Java,
C#,
JavaScript,
TypeScript, TSX,
Scheme, Guile,
Lisp,
EmacsLisp,
@ -403,7 +405,8 @@ For Lua: @code{_}, @code{gettext.gettext}, @code{gettext.dgettext:2},
@code{gettext.dngettext:2,3}, @code{gettext.dcngettext:2,3}.
@item
For JavaScript: @code{_}, @code{gettext}, @code{dgettext:2},
For JavaScript, TypeScript, TSX:
@code{_}, @code{gettext}, @code{dgettext:2},
@code{dcgettext:2}, @code{ngettext:1,2}, @code{dngettext:2,3},
@code{pgettext:1c,2}, @code{dpgettext:2c,3}.
@ -471,6 +474,7 @@ Python,
Java,
C#,
JavaScript,
TypeScript, TSX,
Scheme, Guile,
Lisp,
EmacsLisp,

View File

@ -374,6 +374,14 @@ msgl-check.c
| x-javascript.h
| x-javascript.c
| String extractor for JavaScript.
| x-typescript.h
| x-typescript.c
| x-typescript-impl.h
| String extractor for TypeScript.
| x-typescriptx.h
| x-typescriptx.c
| x-typescript-impl.h
| String extractor for TSX.
| x-scheme.h
| x-scheme.c
| String extractor for Scheme.

View File

@ -41,7 +41,7 @@ else
noinst_LTLIBRARIES = libgettextsrc.la
endif
noinst_LIBRARIES = libxgettextts1.a libxgettextts2.a
noinst_LIBRARIES = $(LIBXGETTEXTTS)
noinst_HEADERS = \
pos.h message.h po-error.h xerror-handler.h po-xerror.h \
@ -76,6 +76,9 @@ noinst_HEADERS = \
x-java.h \
x-csharp.h \
x-javascript.h \
x-typescript.h \
x-typescriptx.h \
x-typescript-impl.h \
x-scheme.h \
x-lisp.h \
x-elisp.h \
@ -240,7 +243,7 @@ libgettextsrc_la_SOURCES = \
search-path.c
# xgettext has some tree-sitter based backends.
LIBXGETTEXTTS = libxgettextts2.a libxgettextts1.a
LIBXGETTEXTTS = libxgettextts2.a libxgettextts3.a libxgettextts4.a libxgettextts1.a
libxgettextts1_a_SOURCES = \
../tree-sitter-$(TREE_SITTER_VERSION)/lib/src/lib.c
libxgettextts1_a_CPPFLAGS = \
@ -252,6 +255,18 @@ libxgettextts2_a_SOURCES = \
../tree-sitter-go-$(TREE_SITTER_GO_VERSION)/src/go-parser.c
libxgettextts2_a_CPPFLAGS = \
-I$(top_srcdir)/tree-sitter-$(TREE_SITTER_VERSION)/lib/include
libxgettextts3_a_SOURCES = \
../tree-sitter-typescript-$(TREE_SITTER_TYPESCRIPT_VERSION)/typescript/src/ts-parser.c \
../tree-sitter-typescript-$(TREE_SITTER_TYPESCRIPT_VERSION)/typescript/src/ts-scanner.c
libxgettextts3_a_CPPFLAGS = \
-I$(top_srcdir)/tree-sitter-typescript-$(TREE_SITTER_TYPESCRIPT_VERSION)/typescript/src \
-I$(top_srcdir)/tree-sitter-$(TREE_SITTER_VERSION)/lib/include
libxgettextts4_a_SOURCES = \
../tree-sitter-typescript-$(TREE_SITTER_TYPESCRIPT_VERSION)/tsx/src/tsx-parser.c \
../tree-sitter-typescript-$(TREE_SITTER_TYPESCRIPT_VERSION)/tsx/src/tsx-scanner.c
libxgettextts4_a_CPPFLAGS = \
-I$(top_srcdir)/tree-sitter-typescript-$(TREE_SITTER_TYPESCRIPT_VERSION)/tsx/src \
-I$(top_srcdir)/tree-sitter-$(TREE_SITTER_VERSION)/lib/include
# msggrep needs pattern matching.
LIBGREP = ../libgrep/libgrep.a
@ -294,6 +309,8 @@ xgettext_SOURCES += \
x-java.c \
x-csharp.c \
x-javascript.c \
x-typescript.c \
x-typescriptx.c \
x-scheme.c \
x-lisp.c \
x-elisp.c \

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,31 @@
/* xgettext TypeScript backend.
Copyright (C) 2001-2025 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Written by Bruno Haible <bruno@clisp.org>, 2025. */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
/* Specification. */
#include "x-typescript.h"
#define NOTE_OPTION_KEYWORD x_typescript_keyword
#define NOTE_OPTION_EXTRACT_ALL x_typescript_extract_all
#define INIT_FLAG_TABLE init_flag_table_typescript
#define EXTRACT extract_typescript
#define TREE_SITTER_LANGUAGE tree_sitter_typescript
#include "x-typescript-impl.h"

View File

@ -0,0 +1,52 @@
/* xgettext TypeScript backend.
Copyright (C) 2002-2025 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Written by Bruno Haible <bruno@clisp.org>, 2025. */
#include <stdio.h>
#include "message.h"
#include "xg-arglist-context.h"
#ifdef __cplusplus
extern "C" {
#endif
#define EXTENSIONS_TYPESCRIPT \
{ "ts", "TypeScript" }, \
#define SCANNERS_TYPESCRIPT \
{ "TypeScript", extract_typescript, NULL, \
&flag_table_typescript, &formatstring_javascript, NULL }, \
/* Scan a TypeScript file and add its translatable strings to mdlp. */
extern void extract_typescript (FILE *fp, const char *real_filename,
const char *logical_filename,
flag_context_list_table_ty *flag_table,
msgdomain_list_ty *mdlp);
extern void x_typescript_keyword (const char *keyword);
extern void x_typescript_extract_all (void);
extern void init_flag_table_typescript (void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,31 @@
/* xgettext TSX backend.
Copyright (C) 2001-2025 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Written by Bruno Haible <bruno@clisp.org>, 2025. */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
/* Specification. */
#include "x-typescriptx.h"
#define NOTE_OPTION_KEYWORD x_typescriptx_keyword
#define NOTE_OPTION_EXTRACT_ALL x_typescriptx_extract_all
#define INIT_FLAG_TABLE init_flag_table_typescriptx
#define EXTRACT extract_typescriptx
#define TREE_SITTER_LANGUAGE tree_sitter_tsx
#include "x-typescript-impl.h"

View File

@ -0,0 +1,52 @@
/* xgettext TSX backend.
Copyright (C) 2002-2025 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Written by Bruno Haible <bruno@clisp.org>, 2025. */
#include <stdio.h>
#include "message.h"
#include "xg-arglist-context.h"
#ifdef __cplusplus
extern "C" {
#endif
#define EXTENSIONS_TYPESCRIPTX \
{ "tsx", "TSX" }, \
#define SCANNERS_TYPESCRIPTX \
{ "TSX", extract_typescriptx, NULL, \
&flag_table_typescriptx, &formatstring_javascript, NULL }, \
/* Scan a TSX file and add its translatable strings to mdlp. */
extern void extract_typescriptx (FILE *fp, const char *real_filename,
const char *logical_filename,
flag_context_list_table_ty *flag_table,
msgdomain_list_ty *mdlp);
extern void x_typescriptx_keyword (const char *keyword);
extern void x_typescriptx_extract_all (void);
extern void init_flag_table_typescriptx (void);
#ifdef __cplusplus
}
#endif

View File

@ -107,6 +107,8 @@
#include "x-java.h"
#include "x-csharp.h"
#include "x-javascript.h"
#include "x-typescript.h"
#include "x-typescriptx.h"
#include "x-scheme.h"
#include "x-lisp.h"
#include "x-elisp.h"
@ -194,6 +196,8 @@ static flag_context_list_table_ty flag_table_python;
static flag_context_list_table_ty flag_table_java;
static flag_context_list_table_ty flag_table_csharp;
static flag_context_list_table_ty flag_table_javascript;
static flag_context_list_table_ty flag_table_typescript;
static flag_context_list_table_ty flag_table_typescriptx;
static flag_context_list_table_ty flag_table_scheme;
static flag_context_list_table_ty flag_table_lisp;
static flag_context_list_table_ty flag_table_elisp;
@ -392,6 +396,8 @@ main (int argc, char *argv[])
init_flag_table_java ();
init_flag_table_csharp ();
init_flag_table_javascript ();
init_flag_table_typescript ();
init_flag_table_typescriptx ();
init_flag_table_scheme ();
init_flag_table_lisp ();
init_flag_table_elisp ();
@ -436,6 +442,8 @@ main (int argc, char *argv[])
x_ruby_extract_all ();
x_lua_extract_all ();
x_javascript_extract_all ();
x_typescript_extract_all ();
x_typescriptx_extract_all ();
x_vala_extract_all ();
break;
@ -518,6 +526,8 @@ main (int argc, char *argv[])
x_ruby_keyword (optarg);
x_lua_keyword (optarg);
x_javascript_keyword (optarg);
x_typescript_keyword (optarg);
x_typescriptx_keyword (optarg);
x_vala_keyword (optarg);
x_desktop_keyword (optarg);
if (optarg == NULL)
@ -1137,11 +1147,11 @@ Choice of input file language:\n"));
printf (_("\
-L, --language=NAME recognise the specified language\n\
(C, C++, ObjectiveC, PO, Python, Java,\n\
JavaProperties, C#, JavaScript, Scheme, Guile,\n\
Lisp, EmacsLisp, librep, Rust, Go, Ruby, Shell,\n\
awk, Lua, Smalltalk, Vala, Tcl, Perl, PHP,\n\
GCC-source, YCP, NXStringTable, RST, RSJ,\n\
Glade, GSettings, Desktop)\n"));
JavaProperties, C#, JavaScript, TypeScript, TSX,\n\
Scheme, Guile, Lisp, EmacsLisp, librep, Rust,\n\
Go, Ruby, Shell, awk, Lua, Smalltalk, Vala, Tcl,\n\
Perl, PHP, GCC-source, YCP, NXStringTable, RST,\n\
RSJ, Glade, GSettings, Desktop)\n"));
printf (_("\
-C, --c++ shorthand for --language=C++\n"));
printf (_("\
@ -1181,27 +1191,27 @@ Language specific options:\n"));
-a, --extract-all extract all strings\n"));
printf (_("\
(only languages C, C++, ObjectiveC, Python,\n\
Java, C#, JavaScript, Scheme, Guile, Lisp,\n\
EmacsLisp, librep, Rust, Go, Shell, awk, Lua,\n\
Vala, Tcl, Perl, PHP, GCC-source, Glade,\n\
GSettings)\n"));
Java, C#, JavaScript, TypeScript, TSX, Scheme,\n\
Guile, Lisp, EmacsLisp, librep, Rust, Go, Shell,\n\
awk, Lua, Vala, Tcl, Perl, PHP, GCC-source,\n\
Glade, GSettings)\n"));
printf (_("\
-kWORD, --keyword=WORD look for WORD as an additional keyword\n\
-k, --keyword do not to use default keywords\n"));
printf (_("\
(only languages C, C++, ObjectiveC, Python,\n\
Java, C#, JavaScript, Scheme, Guile, Lisp,\n\
EmacsLisp, librep, Rust, Go, Shell, awk, Lua,\n\
Vala, Tcl, Perl, PHP, GCC-source, Glade,\n\
GSettings, Desktop)\n"));
Java, C#, JavaScript, TypeScript, TSX, Scheme,\n\
Guile, Lisp, EmacsLisp, librep, Rust, Go, Shell,\n\
awk, Lua, Vala, Tcl, Perl, PHP, GCC-source,\n\
Glade, GSettings, Desktop)\n"));
printf (_("\
--flag=WORD:ARG:FLAG additional flag for strings inside the argument\n\
number ARG of keyword WORD\n"));
printf (_("\
(only languages C, C++, ObjectiveC, Python,\n\
Java, C#, JavaScript, Scheme, Guile, Lisp,\n\
EmacsLisp, librep, Rust, Go, Shell, awk, Lua,\n\
Vala, Tcl, Perl, PHP, GCC-source, YCP)\n"));
Java, C#, JavaScript, TypeScript, TSX, Scheme,\n\
Guile, Lisp, EmacsLisp, librep, Rust, Go, Shell,\n\
awk, Lua, Vala, Tcl, Perl, PHP, GCC-source, YCP)\n"));
printf (_("\
--tag=WORD:FORMAT defines the behaviour of tagged template literals\n\
with tag WORD\n"));
@ -1664,6 +1674,12 @@ xgettext_record_flag (const char *optionstring)
flag_context_list_table_insert (&flag_table_javascript, XFORMAT_PRIMARY,
name_start, name_end,
argnum, value, pass);
flag_context_list_table_insert (&flag_table_typescript, XFORMAT_PRIMARY,
name_start, name_end,
argnum, value, pass);
flag_context_list_table_insert (&flag_table_typescriptx, XFORMAT_PRIMARY,
name_start, name_end,
argnum, value, pass);
break;
case format_scheme:
flag_context_list_table_insert (&flag_table_scheme, XFORMAT_PRIMARY,
@ -2319,6 +2335,8 @@ language_to_extractor (const char *name)
SCANNERS_JAVA
SCANNERS_CSHARP
SCANNERS_JAVASCRIPT
SCANNERS_TYPESCRIPT
SCANNERS_TYPESCRIPTX
SCANNERS_SCHEME
SCANNERS_LISP
SCANNERS_ELISP
@ -2414,6 +2432,8 @@ extension_to_language (const char *extension)
EXTENSIONS_JAVA
EXTENSIONS_CSHARP
EXTENSIONS_JAVASCRIPT
EXTENSIONS_TYPESCRIPT
EXTENSIONS_TYPESCRIPTX
EXTENSIONS_SCHEME
EXTENSIONS_LISP
EXTENSIONS_ELISP

View File

@ -182,6 +182,9 @@ TESTS = gettext-1 gettext-2 \
xgettext-tcl-5 \
xgettext-tcl-stackovfl-1 xgettext-tcl-stackovfl-2 \
xgettext-tcl-stackovfl-3 xgettext-tcl-stackovfl-4 \
xgettext-typescript-1 xgettext-typescript-2 xgettext-typescript-3 \
xgettext-typescript-4 xgettext-typescript-5 xgettext-typescript-6 \
xgettext-typescript-7 \
xgettext-vala-1 xgettext-vala-2 xgettext-vala-3 xgettext-vala-4 \
xgettext-vala-5 xgettext-vala-6 xgettext-vala-7 \
xgettext-vala-stackovfl-1 xgettext-vala-stackovfl-2 \

View File

@ -1,7 +1,7 @@
#!/bin/sh
. "${srcdir=.}/init.sh"; path_prepend_ . ../src
# Test of JavaScript JSX support.
# Test of JavaScript E4X and JSX support.
cat <<\EOF > xg-js-6.js
class Foo extends React.Component {
@ -22,6 +22,8 @@ class Bar extends React.Component {
}
}
// Some E4X tests.
var x1 = <x1></x1>;
var s1 = _("Expected translation string #1");
var s2 = "foo";
@ -48,7 +50,9 @@ function foo() {
return <a>{ 'b' }</a>;
}
var s10 = _("Expected translation string #9");
// Mixing JSX with template literals.
var s11 = 0;
var s12 = (
<div>

View File

@ -0,0 +1,68 @@
#!/bin/sh
. "${srcdir=.}/init.sh"; path_prepend_ . ../src
# Test of TypeScript support.
cat <<\EOF > xg-ts-1.ts
const s1: string = "Simple string, no gettext needed";
const s2: string = _("Extract this first string");
function foo(a: any): void {
const s3: string = `Prefix _(${_("Extract this second string")}) Postfix`;
}
const fooElement = document.getElementById("foo");
if (fooElement && fooElement.innerHTML === _("Extract this third string")) {
/* _("This is a comment and must not be extracted!") */
}
/* TRANSLATORS: This is a translator comment. */
gettext("Extract this fourth string");
// TRANSLATORS: This is another translator comment.
gettext("Extract this fifth string");
EOF
: ${XGETTEXT=xgettext}
${XGETTEXT} --add-comments=TRANSLATORS: --no-location -o xg-ts-1.tmp xg-ts-1.ts 2>xg-ts-1.err
test $? = 0 || { cat xg-ts-1.err; Exit 1; }
func_filter_POT_Creation_Date xg-ts-1.tmp xg-ts-1.pot
cat <<\EOF > xg-ts-1.ok
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Extract this first string"
msgstr ""
msgid "Extract this second string"
msgstr ""
msgid "Extract this third string"
msgstr ""
#. TRANSLATORS: This is a translator comment.
msgid "Extract this fourth string"
msgstr ""
#. TRANSLATORS: This is another translator comment.
msgid "Extract this fifth string"
msgstr ""
EOF
: ${DIFF=diff}
${DIFF} xg-ts-1.ok xg-ts-1.pot
result=$?
exit $result

View File

@ -0,0 +1,110 @@
#!/bin/sh
. "${srcdir=.}/init.sh"; path_prepend_ . ../src
# Test of TypeScript support.
# Playing with regex and division operator
cat <<\EOF > xg-ts-2.ts
// RegExp literals containing string quotes must not desync the parser
const d: number = 1 / 2 / 4;
const s: string = " x " + (/^\d/.exec("0815")?.[0] || "").replace(/[a-z]/g, '@');
const s1: RegExpMatchArray | null = /"/.exec(_("RegExp test string #1"));
const s2: RegExpMatchArray | null = /'/.exec(_("RegExp test string #2"));
const s3: RegExpMatchArray | null = /['a-b]/.exec(_('RegExp test string #3'));
const s4: RegExpMatchArray | null = /["a-b]/.exec(_('RegExp test string #4'));
const s5: RegExpMatchArray | null = /[a-b']/.exec(_('RegExp test string #5'));
const s6: RegExpMatchArray | null = /[a-b"]/.exec(_('RegExp test string #6'));
const c: number = 35 / 2 / 8 + _( "RegExp test string #7").length / 32.0;
const sizestr: string = Math.round(size/1024*factor)/factor+_( "RegExp test string #8");
const cssClassType: string = attr.type.replace(/^.*\//, _('RegExp test string #9')).replace(/\./g, '-');
const lookup: number = lookuptable[idx]/factor+_( "RegExp test string #10");
function doit(): RegExpMatchArray | null {
return /\./.exec(_("RegExp test string #11"));
}
if (false)
/foo/.exec(_("RegExp test string #12"));
else
/foo/.exec(_("RegExp test string #13"));
const s7: boolean = /a\/\f\r\n\t\v\0\b\s\S\w\W\d\D\b\Bb/.test(_("RegExp test string #14"));
const s8: RegExpExecArray | null = /(?=(a+))a*b\1/.exec(_("RegExp test string #15"));
const s9: RegExpExecArray | null = /_\("a+"\)/.exec(_("RegExp test string #16"));
EOF
: ${XGETTEXT=xgettext}
${XGETTEXT} --add-comments --no-location -o xg-ts-2.tmp xg-ts-2.ts 2>xg-ts-2.err
test $? = 0 || { cat xg-ts-2.err; Exit 1; }
func_filter_POT_Creation_Date xg-ts-2.tmp xg-ts-2.pot
cat <<\EOF > xg-ts-2.ok
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "RegExp test string #1"
msgstr ""
msgid "RegExp test string #2"
msgstr ""
msgid "RegExp test string #3"
msgstr ""
msgid "RegExp test string #4"
msgstr ""
msgid "RegExp test string #5"
msgstr ""
msgid "RegExp test string #6"
msgstr ""
msgid "RegExp test string #7"
msgstr ""
msgid "RegExp test string #8"
msgstr ""
msgid "RegExp test string #9"
msgstr ""
msgid "RegExp test string #10"
msgstr ""
msgid "RegExp test string #11"
msgstr ""
msgid "RegExp test string #12"
msgstr ""
msgid "RegExp test string #13"
msgstr ""
msgid "RegExp test string #14"
msgstr ""
msgid "RegExp test string #15"
msgstr ""
msgid "RegExp test string #16"
msgstr ""
EOF
: ${DIFF=diff}
${DIFF} xg-ts-2.ok xg-ts-2.pot
result=$?
exit $result

View File

@ -0,0 +1,74 @@
#!/bin/sh
. "${srcdir=.}/init.sh"; path_prepend_ . ../src
# Test of TypeScript support: string concatenation,
# strings with embedded expressions.
cat <<\EOF > xg-ts-3.ts
let s0: string;
let s1: string = _("Concatenation #1 " + "- String part added");
let s2: string = _('Concatenation #2 ' + '- String part added');
// a
let s3: string = // b
_("This" + " whole " // c
+ "string" + // d
' should' + " be " + 'extracted');
// Strings with embedded expressions, a.k.a. template literals.
let t: string = "";
let e1: string = _(`embedded_1_${foo}_bar`);
let e2: string = _(`embedded_2_${_("embedded_2_sub1")}_bar_${_('embedded_2_sub2')}_baz`);
let e3: string = _(`embedded_3`);
EOF
: ${XGETTEXT=xgettext}
${XGETTEXT} --add-comments --no-location -o xg-ts-3.tmp xg-ts-3.ts 2>xg-ts-3.err
test $? = 0 || { cat xg-ts-3.err; Exit 1; }
func_filter_POT_Creation_Date xg-ts-3.tmp xg-ts-3.pot
cat <<\EOF > xg-ts-3.ok
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Concatenation #1 - String part added"
msgstr ""
msgid "Concatenation #2 - String part added"
msgstr ""
#. a
#. b
msgid "This whole string should be extracted"
msgstr ""
msgid "embedded_2_sub1"
msgstr ""
msgid "embedded_2_sub2"
msgstr ""
msgid "embedded_3"
msgstr ""
EOF
: ${DIFF=diff}
${DIFF} xg-ts-3.ok xg-ts-3.pot
result=$?
exit $result

View File

@ -0,0 +1,51 @@
#!/bin/sh
. "${srcdir=.}/init.sh"; path_prepend_ . ../src
# Test of TypeScript escape sequences in string literals.
cat <<\EOF > xg-ts-4.ts
const s1: string = _("Unicode escape \u3042");
const s2: string = _("Surrogate pair \uD835\uDC9C");
const s3: string = _("Escape sequence \1411 \x622");
const s4: string = _("Invalid escape sequence \xxx \y");
EOF
: ${XGETTEXT=xgettext}
${XGETTEXT} --add-comments --no-location -o xg-ts-4.tmp xg-ts-4.ts 2>xg-ts-4.err
test $? = 0 || { cat xg-ts-4.err; Exit 1; }
func_filter_POT_Creation_Date xg-ts-4.tmp xg-ts-4.pot
cat <<\EOF > xg-ts-4.ok
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Unicode escape あ"
msgstr ""
msgid "Surrogate pair 𝒜"
msgstr ""
msgid "Escape sequence a1 b2"
msgstr ""
EOF
: ${DIFF=diff}
${DIFF} xg-ts-4.ok xg-ts-4.pot
result=$?
exit $result

View File

@ -0,0 +1,69 @@
#!/bin/sh
. "${srcdir=.}/init.sh"; path_prepend_ . ../src
# Test of TypeScript Unicode support.
cat <<\EOF > xg-ts-5.ts
// The following excerpt is adapted from json2.js
const cx: RegExp = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
const escapable: RegExp = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
let gap: string | undefined;
const txt1: string = _("Expected translation string #1");
let indent: string | undefined;
const meta: Record<string, string> = {
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"': '\\"',
'\\': '\\\\' + _("Expected translation string #2")
};
const txt2: string = _("Expected translation string #3");
let rep: any;
const matched: string = curnodepath.match(new RegExp(`^\\${path}\/([\\w\\s]+)`))
+ _("Expected translation string #4");
EOF
: ${XGETTEXT=xgettext}
${XGETTEXT} --add-comments --no-location -o xg-ts-5.tmp xg-ts-5.ts 2>xg-ts-5.err
test $? = 0 || { cat xg-ts-5.err; Exit 1; }
func_filter_POT_Creation_Date xg-ts-5.tmp xg-ts-5.pot
cat <<\EOF > xg-ts-5.ok
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Expected translation string #1"
msgstr ""
msgid "Expected translation string #2"
msgstr ""
msgid "Expected translation string #3"
msgstr ""
msgid "Expected translation string #4"
msgstr ""
EOF
: ${DIFF=diff}
${DIFF} xg-ts-5.ok xg-ts-5.pot
result=$?
exit $result

View File

@ -0,0 +1,157 @@
#!/bin/sh
. "${srcdir=.}/init.sh"; path_prepend_ . ../src
# Test of TypeScript JSX support.
cat <<\EOF > xg-ts-6.tsx
import React from 'react';
type FooProps = {};
type FooState = {};
class Foo extends React.Component<FooProps, FooState> {
render() {
return <div className="aClass" />;
}
}
type BarProps = {};
type BarState = {};
class Bar extends React.Component<BarProps, BarState> {
render() {
return (
<div>
<span className="someClass" />
{ gettext('Expected translation string #0') }
</div>
);
}
}
const x1 = <x1></x1>;
const s1: string = _("Expected translation string #1");
const s2: string = "foo";
const x2 = React.createElement(s2 as any, null, `foo ${s2} bar`);
const x3 = (
<x3 a1="/">
<x4>{_("Expected translation string #2")}</x4>
</x3>
);
const x4 = (
<x5 a2="/">
{React.createElement(_("Expected translation string #3") as any)}
</x5>
);
const s9: string = _("Expected translation string #8");
function fooFunction() {
return <a>{'b'}</a>;
}
const s10: string = _("Expected translation string #9");
// Mixing JSX with template literals.
const s11 = 0;
const s12 = (
<div>
{_("Expected translation string #10")}
{`${_("Expected translation string #11")}`}
{_("Expected translation string #12")}
</div>
);
const s13: string = _("Expected translation string #13");
const s14 = <div className={`${_("Expected translation string #14")}`} />;
const s15: string = _("Expected translation string #15");
const s16 = { a: 1, b: <div className={`${_("Expected translation string #16")}`} /> };
const s17: string = _("Expected translation string #17");
const s18 = `begin${<div>{_("Expected translation string #18")}</div>}end`;
const s19: string = _("Expected translation string #19");
const s20 = () => (
<Foo
a1={_("Expected translation string #20")}
a2={foo && <div>{_("Expected translation string #21")}</div>}
a3={_("Expected translation string #22")}
/>
);
EOF
: ${XGETTEXT=xgettext}
${XGETTEXT} --add-comments --no-location -o xg-ts-6.tmp xg-ts-6.tsx 2>xg-ts-6.err
test $? = 0 || { cat xg-ts-6.err; Exit 1; }
func_filter_POT_Creation_Date xg-ts-6.tmp xg-ts-6.pot
cat <<\EOF > xg-ts-6.ok
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Expected translation string #0"
msgstr ""
msgid "Expected translation string #1"
msgstr ""
msgid "Expected translation string #2"
msgstr ""
msgid "Expected translation string #3"
msgstr ""
msgid "Expected translation string #8"
msgstr ""
msgid "Expected translation string #9"
msgstr ""
msgid "Expected translation string #10"
msgstr ""
msgid "Expected translation string #11"
msgstr ""
msgid "Expected translation string #12"
msgstr ""
msgid "Expected translation string #13"
msgstr ""
msgid "Expected translation string #14"
msgstr ""
msgid "Expected translation string #15"
msgstr ""
msgid "Expected translation string #16"
msgstr ""
msgid "Expected translation string #17"
msgstr ""
msgid "Expected translation string #18"
msgstr ""
msgid "Expected translation string #19"
msgstr ""
msgid "Expected translation string #20"
msgstr ""
msgid "Expected translation string #21"
msgstr ""
msgid "Expected translation string #22"
msgstr ""
EOF
: ${DIFF=diff}
${DIFF} xg-ts-6.ok xg-ts-6.pot
result=$?
exit $result

View File

@ -0,0 +1,90 @@
#!/bin/sh
. "${srcdir=.}/init.sh"; path_prepend_ . ../src
# Test of TypeScript template literal support.
cat <<\EOF > xg-ts-7.ts
const s0: string = _(`A template literal without substitutions`);
const s1: string = _(`A template literal with
embedded
newlines`);
const s2: string = _(`A template literal with ${n} substitutions`);
const s3: string = _(`A template literal with several substitutions: ${a} and ${b} and ${c} and so on`);
const s4: string = `/${looks_like_regex}`;
const s5: string = _('not part of a regex');
const s6: string = `that's a valid string. ` + _('This too');
const s7: string = _(tag`A template literal with a tag`);
const s8: string = `a${`b${`c`+d}`}e`;
const s9: string = _("a normal string");
const s10: string = `abc${foo({}, _('should be extracted'))}xyz`;
const f1 = function (): string {
return _("first normal string") + `${foo}` + _("second normal string");
};
const s11: string = _("another normal string");
const s12: { property: string } = { property: `A template literal with ${n} substitution` };
const s13: string = _("yet another normal string");
EOF
: ${XGETTEXT=xgettext}
${XGETTEXT} --add-comments --no-location -o xg-ts-7.tmp xg-ts-7.ts 2>xg-ts-7.err
test $? = 0 || { cat xg-ts-7.err; Exit 1; }
func_filter_POT_Creation_Date xg-ts-7.tmp xg-ts-7.pot
cat <<\EOF > xg-ts-7.ok
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "A template literal without substitutions"
msgstr ""
msgid ""
"A template literal with\n"
"embedded\n"
"newlines"
msgstr ""
msgid "not part of a regex"
msgstr ""
msgid "This too"
msgstr ""
msgid "a normal string"
msgstr ""
msgid "should be extracted"
msgstr ""
msgid "first normal string"
msgstr ""
msgid "second normal string"
msgstr ""
msgid "another normal string"
msgstr ""
msgid "yet another normal string"
msgstr ""
EOF
: ${DIFF=diff}
${DIFF} xg-ts-7.ok xg-ts-7.pot
result=$?
exit $result