I'm using i18next to internationalize my React web application with typescript. When I process the text, it outputs the following:
Running string extraction on source files
Finding source files to process
Running xgettext
Extracting text for language en
Translation file was found - merging translations
..............................
Read 1 old + 1 reference, merged 266, fuzzied 0, missing 30, obsolete 27.
Running xgettext
Extracting text for language fr
Translation file was found - merging translations
..............................
[... other languages]
So I have 30 keys that are missing, but somehow I can't find a way to know exactly which 30 string keys are missing...
The only way I can currently find a missing key is if I open the console of my browser and when one of my React components is rendered if it contains a missing key, it prints:
i18next::translator: missingKey en translation my_missing_string my_missing_string
(Yes it prints it twice on the same line)
But, I am not going to try and render every single possible component depending on use cases since we have over 300 different strings.
How is i18next able to tell me that 30 are missing but not able to show which ones, I must be missing somthing.
what extraction tool are you using? seems to be from some gettext implementation - not related to i18next...
try one of those:
https://github.com/i18next/i18next-parser
https://github.com/i18next/i18next-scanner
This solution proposes another approach, which works great for our team : using translation files as a type, to validate parameters of the translation function.
So instead of finding missing keys, TpeScript will be able to tell you that the key you just entered does not exist.
Related
Sorry this will be a super newbie question.
In the default.ctp layout file, towards the beginning there are two lines.
$cakeDescription = __d('cake_dev', 'CakePHP: the rapid development php framework');
$cakeVersion = __d('cake_dev', 'CakePHP %s', Configure::version())
I've found the function for __d here which says it "Allows you to override the current domain for a single message lookup." I don't really understand what it means at all.
Additionally, I was able to do the same thing without throwing any errors by simply replacing the lines with
$cakeDescription = 'CakePHP: the rapid development php framework';
$cakeVersion = 'CakePHP ' . Configure::version();
Its used for making your application multilingual.
You can use the command Console/cake i18n extract to extract all the text strings(which is the second parameter in __d()) into a pot file, which you can then translate.
See this for more information about __d() https://book.cakephp.org/2.0/en/core-libraries/internationalization-and-localization.html#internationalizing-cakephp-plugins
And see this for more information about extracting the strings into pot files
https://book.cakephp.org/2.0/en/console-and-shells/i18n-shell.html
I am using the Drupal 7 Migrate module to create a series of nodes from JPG and EPS files. I can get them to import just fine. But I notice that when I am done importing them if I look at the nodes it creates, none of the attached filefield and thumbnail files contain filename information.
Upon inspecting the file_managed table I see that both the filename and filemime fields are empty for ONLY the files that I attached via the migrate module. This also creates an issue with downloading the files.
Now I think the problem has to do with the fact that I am using "file_link" instead of "file_copy" as the file operation I specify. The problem is I am importing around 2TB (thats Terabytes) of image files. We had to put in a special request with Rackspace just to get access to that much disk space on our server. So I can't go around copying from one directory to the next because of space issues. So "file_link" seems like the obvious choice.
Now you probably want to see how I am doing this exactly, so here is the code snippet:
$jpg_arguments = MigrateFileFieldHandler::arguments(NULL,
'file_link', FILE_EXISTS_RENAME, 'en', array('source_field' => 'jpg_name'),
array('source_field' => 'jpg_filename'), array('source_field' => 'jpg_filename'));
$this->addFieldMapping('field_image', 'jpg_uri')
->arguments($jpg_arguments);
As you can see I am specifying no base path (just like the beer.inc example file does). I have set file_link, the language, and the source fields for the description, title, and alt.
It is able to generate thumbnails from the JPGs. But still missing those columns of data in the db table. I traced through the functions the best I could but I don't see what is causing this. I tried running the uri in the table through the functions that generate the filename and the filemime and they output just fine. It is like something is removing just those segments of data.
Does anyone have any idea what this could be? I am using the Drupal 7 Migrate module version 2.2. It is running on Drupal 7.8.
Thanks,
Patrick
Ok, so I have found the answer to yet another question of mine. This is actually an issue with the migrate module itself. The issue is documented here. I will be repealing this bounty (as soon as I figure out how).
I have finally managed to set up a multilingual cakephp site.
Although not finished it is the first time where I can change the DEFAULT_LANGUAGE in the bootstrap and I can see the language to change.
My problem right now is that I cannot understand very well how to use the po files correctly.
According to the tutorials I've used I need to create a folder /app/locale and inside that folder create a folder for each language in the following format: /locale/eng/LC_MESSAGES.
I have done that and I have also managed to extract a default.pot file using cake i18n extract. And it appears that all occurrences of the __() function have been found succesfully.
In my application I'm using 2 languages: eng and gre.
I can see why you would need a seperate folder for each language.
However in my case nothing happens when I edit the po files inside each folder....well almost nothing. If I edit the /app/locale/gre/LC_MESSAGES/default.po I have no language changes. If I edit the /app/locale/eng/LC_MESSAGES/default.po then the language changes to the new value (on the translation field) and it does not switch to the other language.
What am I doing wrong.
I hope I made myself as clear as possible.
There are different ways to go about it. The easiest is to code the app in the primary language and to just wrap all translatable strings in __(). Later you can add .po files for each translation you may want.
The problem with this approach is that if you were to change the text in the original language, you'll also need to change the msgid entry for this string in every .po file you may have. This can become quite cumbersome if you have to support many different languages.
Please disregard the old information above. A properly set up i18n workflow will use xgettext or similar utilities to automatically extract __() wrapped strings from the source code and produce, update and merge .po files. Nothing cumbersome about it.
The alternative is to use a "descriptor" text in the source files and put the actual text in .po files, even for the primary language. I.e:
__('PRODUCT CAPTION');
/eng/.po
msgid "PRODUCT CAPTION"
msgstr "Buy our awesome products!"
/ger/.po
msgid "PRODUCT CAPTION"
msgstr "Kaufen Sie unsere Produkte!"
What works better depends on the project and on you, you'll have to figure it out...
Use
Configure::write('Config.language', 'fr');
to set the language of the user to french.
I'm just beginning the process of exploring i18n in CakePHP and I can't seem to find the right combination of files and functions that will allow me to use multiple po files. If I want to use a single po file (default.po) for every bit of translatable text, that works fine, but I see that becoming an unmaintainable hairball very, very quickly. I've read the docs and the few articles I can find, but none really dive into i18n beyond the trivial use of one .po file.
Here's where I am right now:
I've "baked" my po templates (.pot files) and copied those into app/locale/eng/LC_MESSAGES (I'm not going to be using the default text as the key so that I can easily spot missing keys). For now, I have -views-layouts-default.po and -views-pages-index.po.
In those .po files, I've entered the text I want to use for each key.
In my homepage (views/pages/index.ctp) and default layout (views/layouts/default.ctp) I've wrapped the text key I want to translate with the __() function.
When I load the homepage, though, all I see are they keys. No text has been translated. If I throw up a default.po file, though, any keys I drop in there are populated just fine. I'm clearly missing some piece of the puzzle, but I can't find it. Any help would be much appreciated.
Thanks.
I found the piece I was missing thanks to the CakePHP Google Group. I had been playing with the __d() convenience function, but didn't have a clear picture of how to tie it together to my .po files. The answer is easy once you know it:
The domain translation:
__d ( 'login', 'PLEASE_LOGIN' );
Will look for the "PLEASE_LOGIN" key in the file named login.po. I didn't know (and hadn't read anywhere) that domain == po file name (without extension). Learning that made all the difference.
A friend of mine is now building a web application with J2EE and Struts, and it's going to be prepared to display pages in several languages.
I was told that the best way to support a multi-language site is to use a properties file where you store all the strings of your pages, something like:
welcome.english = "Welcome!"
welcome.spanish = "¡Bienvenido!"
...
This solution is ok, but what happens if your site displays news or something like that (a blog)? I mean, content that is not static, that is updated often... The people that keep the site have to write every new entry in each supported language, and store each version of the entry in the database. The application loads only the entries in the user's chosen language.
How do you design the database to support this kind of implementation?
Thanks.
Warning: I'm not a java hacker, so YMMV but...
The problem with using a list of "properties" is that you need a lot of discipline. Every time you add a string that should be output to the user you will need to open your properties file, look to see if that string (or something roughly equivalent to it) is already in the file, and then go and add the new property if it isn't. On top of this, you'd have to hope the properties file was fairly human readable / editable if you wanted to give it to an external translation team to deal with.
The database based approach is useful for all your database based content. Ideally you want to make it easy to tie pieces of content together with their translations. It only really falls down for all the places you may want to output something that isn't out of a database (error messages etc.).
One fairly old technology which we find still works really well, is to use gettext. Gettext or some variant seems to be available for most languages and platforms. The basic premise is that you wrap your output in a special function call like so:
echo _("Please do not press this button again");
Then running the gettext tools over your source code will extract all the instances wrapped like that into a "po" file. This will contain entries such as:
#: myfolder/my.source:239
msgid "Please do not press this button again"
msgstr ""
And you can add your translation to the appropriate place:
#: myfolder/my.source:239
msgid "Please do not press this button again"
msgstr "s’il vous plaît ne pas appuyer sur le bouton ci-dessous à nouveau"
Subsequent runs of the gettext tools simply update your po files. You don't even need to extract the po file from your source. If you know you may want to translate your site down the line, then you can just use the format shown above (the underscored function) with all your output. If you don't provide a po file it will just return whatever you put in the quotes. gettext is designed to work with locales so the users locale is used to retrieve the appropriate po file. This makes it really easy to add new translations.
Gettext Pros
Doesn't get in your way while coding
Very easy to add translations
PO files can be compiled down for speed
There are libraries available for most languages / platforms
There are good cross platform tools for dealing with translations. It is actually possible to get your translation team set up with a tool such as poEdit to make it very easy for them to manage translation projects
Gettext Cons
Solves your site "furniture" needs, but you would usually still want a database based approach for your database driven content
For more info on gettext see this wikipedia page
They way I have designed the database before is to have an News-table containing basic info like NewsID (int), NewsPubDate (datetime), NewsAuthor (varchar/int) and then have a linked table NewsText that has these columns: NewsID(int), NewsText(text), NewsLanguageID(int). And at last you have a Language-table that has LanguageID(int) and LanguageName(varchar).
Then, when you want to show your users the news-page you do:
SELECT NewsText FROM News INNER JOIN NewsText ON News.NewsID = NewsText.NewsID
WHERE NewsText.NewsLanguageID = <<Session["UserLanguageID"]>>
That Session-bit is a local variable where you store the users language when they log in or enters the site for the first time.
Java web applications support internationalization using the java standard tag library.
You've really got 2 problems. Static content and dynamic content.
for static content you can use jstl. It uses java ResourceBundles to accomplish this. I managed to get a Databased backed bundle working with the help of this site.
The second problem is dynamic content.
To solve this problem you'll need to store the data so that you can retrieve different translations based on the user's Locale. (Locale includes Country and Language).
It's not trivial, but it is something you can do with a little planning up front.
#Auron
thats what we apply it to. Our apps are all PHP, but gettext has a long heritage.
Looks like there is a good Java implementation
Tag libraries are fine if you're using JSP, but you can also achieve I18N using a template-based technology such as FreeMarker.